Domanda

Ho due classi di entità annotate nel modo seguente

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

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

Se memorizzo un'istanza della classe 'B', le relazioni vengono archiviate nel database e il getter nella classe 'A' restituirà il sottoinsieme corretto di B. Tuttavia, se apporto modifiche all'elenco di Bs in "A", le modifiche non vengono memorizzate nel database?

La mia domanda è: come posso fare in modo che i cambiamenti in entrambe le classi siano "quotati" " all'altra classe?

EDIT: ho provato diverse varianti di rimozione del parametro mappedBy e di definizione di JoinTable (e colonne), ma non sono stato in grado di trovare la combinazione corretta.

È stato utile?

Soluzione

La risposta più breve sembra essere impossibile e ha senso. In un'associazione bidirezionale bidirezionale un lato deve essere master e viene utilizzato per mantenere le modifiche alla tabella di join sottostante. Poiché JPA non mantiene entrambi i lati dell'associazione, è possibile che si verifichi una situazione di memoria che non può essere ricaricata una volta archiviata nel database. Esempio:

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

Se questo stato potesse essere persistito, si finirebbe con le seguenti voci nella tabella di join:

a1_id, b_id
a2_id, b_id

Ma al momento del caricamento, come farebbe JPA a sapere che intendevi comunicare a b solo a2 e non a1? e che dire di a2 che non dovrebbe sapere di b?

Questo è il motivo per cui devi mantenere tu stesso l'associazione bidirezionale (e rendere impossibile l'esempio di cui sopra, anche in memoria) e JPA persisterà solo in base allo stato di un suo lato.

Altri suggerimenti

Hai specificato le colonne di join inverse?

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

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

Questo presuppone una tabella di join denominata A_B con le colonne A_ID e B_ID.

  

Poiché la relazione è bidirezionale così come l'applicazione si aggiorna   da un lato della relazione, anche l'altro lato dovrebbe essere aggiornato,   ed essere sincronizzato. In JPA, come in Java in generale è il   responsabilità dell'applicazione o del modello a oggetti da mantenere   relazioni. Se l'applicazione si aggiunge a un lato di a   relazione, quindi deve aggiungere all'altro lato.

     

Questo può essere risolto tramite l'aggiunta o l'impostazione di metodi nel modello a oggetti   che gestiscono entrambi i lati delle relazioni, quindi il codice dell'applicazione   non è necessario preoccuparsene. Ci sono due modi per farlo,   puoi solo aggiungere il codice di manutenzione della relazione da un lato   della relazione e usa il setter solo da un lato (come   rendere l'altro lato protetto) o aggiungerlo ad entrambi i lati e assicurarsi   eviti un ciclo infinito.

Fonte: OneToMany # Getters_and_Setters

Hai provato ad aggiungere il parametro mappedBy nel campo A in classe B in questo modo

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

Forse c'è un piccolo errore nella risposta di A_M. Secondo me dovrebbe essere:

   @Entity
   class B { 
   @ManyToMany 
   @JoinTable (
       name="A_B",
       joinColumns = {@JoinColumn(name="B_ID")},
       inverseJoinColumns = {@JoinColumn(name="A_ID")}
   )
   private List a; 
   .. 
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top