2012-03-31 3 views
4

Ich habe zwei Entitäten:Persistierende @OneToMany Beziehungen mit @JoinColumn und @MapKeyColumn

@Entity 
Article { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) 
    @JoinColumn(name="embed_id", referencedColumnName="id") 
    @MapKeyColumn(name = "language") 
    @MapKeyEnumerated(EnumType.ORDINAL) 
    private Map<Language, Locale> locales; 

    Article() { 
     locales.put(Language.CS, new Locale()); 
     locales.put(Language.EN, new Locale()); 
    } 
} 

@Entity 
Locale { 
    @Id 
    private Long embed_id; 

    @Id 
    private Language language; 

    @Column(length = 256) 
    private String name; 
} 

Dank Konstruktor kann ich sicherstellen, dass, sobald ein Article instanziert wird, zwei Locales (mit CascadeType.ALL) sind damit verbunden.

Das Problem kommt, wenn ich versuche, eine solche Einheit bestehen bleiben - ich erhalte:

javax.persistence.EntityExistsException: 
a different object with the same identifier value was already associated 
     with the session: org...Locale#[email protected] 

Das Problem ist, dass weder embed_id haben noch language Werte aus dem Artikel zugewiesen, wenn persistierende und Hibernate sie nicht assoziieren nach beharrlicher Artikel. Wie kann das gemacht werden?

Edit 1:

Ich habe, dass, wenn die embed_id und language manuell eingestellt werden, alles richtig funktioniert. Ich muss nur Hibernate sagen, um den Wert von @JoinColumn und @MapKeyColumn gemäß der @OneToMany Beziehung zu setzen.

Edit 2:

Das Problem mit MapKeyColumn hat eine einfache Lösung:

public void addLocale(Language l, Locale locale) { 
     locale.setLanguage(l); 
     this.locales.put(l); 
} 

Aber ich bin nach wie vor nicht in der Lage, die Locale.embed_id von Article.id zu sagen, überwintern zu verknüpfen.

bearbeiten 3:

Ich kann sehen, dass die ID des Artikels richtig erzeugt wird, aber dann ist es nicht in den Lokalisierungs setzen:

DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: 87, using strategy: org.hibernate.id.SequenceGenerator 
DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: component[language,embedId]{language=0, embedId=null}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator 
DEBUG org.hibernate.event.internal.AbstractSaveEventListener - 
    Generated identifier: component[language,embedId]{language=1, embedId=null}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator 

Antwort

0

Endlich fand ich das Anwswer! Der Trick bestand darin, Setter auf Artikel zu erstellen und Zugriff auf ID wie folgt hinzuzufügen:

@Id 
@Getter 
@Access(AccessType.PROPERTY) 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

public void setId(Long id) { 
    this.id = id; 
    this.getLocale(Language.CS).setEmbedId(id); 
    this.getLocale(Language.EN).setEmbedId(id); 
} 
3

Ich denke, das Problem ist, dass Sie möchte zwei leere Locales beibehalten. Und da Sie keinen Generator für die ID-Felder verwenden, haben die Gebietsschemas den gleichen (leeren) Primärschlüssel und können daher nicht persistiert werden.

+0

Ich weiß, aber wie kann ich Hibernate mitteilen, sie mit dem Schlüssel der Karte zu verknüpfen? Es ist nicht nur Sprache - denn wenn ich es manuell setze, bekomme ich: 'Nullwert in Spalte" embed_id "verletzt Nicht-Null-Einschränkung;' –

+0

Aber 'embed_id' ist nicht unbedingt einzigartig (weil Sie es mit' Sprache' kombinieren um Einzigartigkeit zu erreichen). Wahrscheinlich kann ein nicht eindeutiger Schlüssel nicht der (eindeutige) Schlüssel einer Map sein? –

+0

Es ist einzigartig in Kombination mit Sprache. Der Primärschlüssel ist die Kombination "embed_id, language". –