Mysql
 sql >> Database >  >> RDS >> Mysql

JPA inserisce i risultati padre/figlio in MySQLIntegrityConstraintViolationException

La tua relazione non deve essere bidirezionale. C'è qualche informazione errata nei commenti qui.

Hai anche affermato di aver aggiunto il campo "parentId" nell'entità Child perché presumevi che JPA debba "conoscere" il campo padre in modo che possa impostare il valore. Il problema non è che JPA non sia a conoscenza del campo, in base alle annotazioni che hai fornito. Il problema è che hai fornito "troppe" informazioni sul campo, ma tali informazioni non sono internamente coerenti.

Modifica il campo e l'annotazione in Genitore in:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id")
private List<Child> children;

Quindi rimuovere completamente il "parentId" dall'entità Child. In precedenza era stata specificata un'annotazione JoinTable. Tuttavia, quello che vuoi non è un JoinTable. Un JoinTable creerebbe una terza tabella aggiuntiva per mettere in relazione le due entità tra loro. Quello che vuoi è solo una JoinColumn. Dopo aver aggiunto l'annotazione JoinColumn a un campo che è anche annotato con OneToMany, la tua implementazione JPA saprà che stai aggiungendo un FK nella tabella CHILD. Il problema è che JPA ha una tabella CHILD già definita con una colonna parent_id.

Pensaci che gli stai dando due definizioni contrastanti sia della funzione della tabella CHILD che della colonna parent_id. In un caso, ti è stato detto JPA che è un'entità e parent_id è semplicemente un valore in quell'entità. Nell'altro, hai detto a JPA che la tua tabella CHILD non è un'entità, ma viene utilizzata per creare una relazione di chiave esterna tra la tua tabella CHILD e la tabella PARENT. Il problema è che la tua tabella CHILD esiste già. Quindi, quando stai rendendo persistente la tua entità, le hai detto che parent_id è esplicitamente null (non impostato), ma poi le hai anche detto che il tuo parent_id dovrebbe essere aggiornato per impostare un riferimento di chiave esterna alla tabella padre.

Ho modificato il tuo codice con le modifiche che ho descritto sopra e ho anche chiamato "persiste" invece di "unisci".

Ciò ha prodotto 3 query SQL

insert into PARENT (ID) values (default)
insert into CHILD (ID) values (default)
update CHILD set parent_id=? where ID=?

Questo riflette perfettamente ciò che desideri. Viene creata la voce GENITORE. Viene creata la voce CHILD, quindi il record CHILD viene aggiornato per impostare correttamente la chiave esterna.

Se invece aggiungi l'annotazione

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id", nullable = false)
private List<Child> children;

Quindi eseguirà la seguente query quando inserisce il figlio

insert into CHILD (ID, parent_id) values (default, ?)

impostando così correttamente il tuo FK fin dall'inizio.