2009-05-05 22 views
10

Ich habe zwei Entitätsklassen auf folgende Weise kommentiertenSaving bidirektionale ManyToMany

@Entity 
class A { 
    @ManyToMany(mappedBy="A", cascade=CascadeType.ALL) 
    private List<B> b; 
.. 
} 

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL) 
    private List<A> a; 
.. 
} 

Wenn ich eine Instanz der Klasse ‚B‘ zu speichern, die Beziehungen werden in der Datenbank und der Getter in der Klasse ‚A‘ gespeichert gibt die korrekte Teilmenge von B zurück. Wenn ich jedoch die Liste der Bs in 'A' ändere, werden die Änderungen nicht in der Datenbank gespeichert?

Meine Frage ist, wie kann ich es so machen, dass Änderungen in beiden Klassen in die andere Klasse "kaskadiert" werden?

BEARBEITEN: Ich habe verschiedene Varianten versucht, den mappedBy-Parameter zu entfernen und eine JoinTable (und Spalten) zu definieren, aber ich konnte die richtige Kombination nicht finden.

+0

Welche JPA-Implementierung verwenden Sie? –

Antwort

16

Die kürzeste Antwort scheint zu sein, kann nicht und es ergibt Sinn. In einer bidirektionalen Viele-zu-Viele-Verknüpfung muss eine Seite Master sein und wird verwendet, um Änderungen an der zugrunde liegenden Join-Tabelle beizubehalten. Da JPA nicht beide Seiten der Verknüpfung verwaltet, kann es zu einer Speichersituation kommen, die nach dem Speichern in der Datenbank nicht erneut geladen werden kann. Beispiel:

A a1 = new A(); 
A a2 = new A(); 
B b = new B(); 
a1.getB().add(b); 
b.getA().add(a2); 

Wenn dieser Zustand beibehalten werden könnte, würden Sie mit den folgenden Einträgen in der Join-Tabelle am Ende:

a1_id, b_id 
a2_id, b_id 

Aber beim Laden, wie würde JPA wissen, dass Sie nur dazu gedacht lass b von a2 und nicht von a1 wissen? Und was ist mit a2, die nicht über b wissen sollten?

Deshalb müssen Sie die bidirektionale Assoziation selbst pflegen (und das obige Beispiel unmöglich machen, auch im Speicher) und JPA wird nur basierend auf dem Zustand einer Seite bestehen bleiben.

0

Haben Sie den mappedBy Parameter auf das A-Feld in der Klasse B Hinzufügen tryed wie so

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b") 
    private List<A> a; 
.. 
} 
+0

Dies funktioniert nicht, es handelt sich tatsächlich um eine unzulässige Parametrisierung. Der Parameter mappedBy definiert die Eigentümerschaft des Felds und die Verwendung dieses Parameters für beide Auflistungen ist daher nicht möglich, da sie sich nicht gegenseitig besitzen können. –

3

Haben Sie die inverse Spalten angegeben beitreten?

Das geht von einer Join-Tabelle namens A_B mit den Spalten A_ID und B_ID aus.

+0

Ich hatte diese Lösung auch versucht, aber kein Glück :( –

+2

sollte das mappedBy gleich 'a' Kleinbuchstaben anstelle der Klasse? – Ced

0

Vielleicht gibt es einen kleinen Fehler in der Antwort von A_M. Meiner Meinung nach sollte es sein:

 
    @Entity 
    class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="B_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="A_ID")} 
    ) 
    private List a; 
    .. 
} 
1

Da die Beziehung, um das Anwendungs-Updates eine Seite der Beziehung bidirektional ist, sollte die andere Seite auch aktualisiert werden, und synchron sein. In JPA, wie in Java im Allgemeinen ist es die Verantwortung der Anwendung, oder das Objektmodell, Beziehungen zu pflegen. Wenn Ihre Anwendung eine Seite einer -Beziehung hinzufügt, muss sie auf der anderen Seite hinzugefügt werden.

Dies kann durch Hinzufügen oder Setzen Methoden im Objektmodell gelöst werden, die beide Seiten der Beziehungen behandeln, so muss sich der Anwendungscode nicht darum kümmern.Es gibt zwei Möglichkeiten, um dies zu umgehen, Sie können entweder nur die Beziehung Wartungscode auf der einen Seite der Beziehung hinzufügen, und nur den Setter von einer Seite (wie macht die andere Seite geschützt), oder fügen Sie es hinzu beide Seiten und sicherstellen, Sie vermeiden eine Endlosschleife.

Quelle: OneToMany#Getters_and_Setters