Mysql
 sql >> Datenbank >  >> RDS >> Mysql

JPA fügt Eltern/Kind-Ergebnisse in MySQLIntegrityConstraintViolationException ein

Ihre Beziehung muss nicht bidirektional sein. Es gibt einige Fehlinformationen in den Kommentaren hier.

Sie sagten auch, dass Sie das Feld "parentId" zur untergeordneten Entität hinzugefügt haben, weil Sie davon ausgegangen sind, dass JPA das übergeordnete Feld "kennen" muss, damit es den Wert festlegen kann. Das Problem ist nicht, dass JPA das Feld nicht kennt, basierend auf den von Ihnen bereitgestellten Anmerkungen. Das Problem besteht darin, dass Sie "zu viele" Informationen über das Feld bereitgestellt haben, diese Informationen jedoch nicht intern konsistent sind.

Ändern Sie Ihr Feld und Ihre Anmerkung in Parent zu:

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

Entfernen Sie dann die „parentId“ vollständig aus der untergeordneten Entität. Sie hatten zuvor eine JoinTable-Anmerkung angegeben. Was Sie jedoch wollen, ist kein JoinTable. Eine JoinTable würde eine zusätzliche dritte Tabelle erstellen, um die beiden Entitäten miteinander in Beziehung zu setzen. Was Sie wollen, ist nur eine JoinColumn. Sobald Sie die JoinColumn-Annotation zu einem Feld hinzufügen, das ebenfalls mit OneToMany annotiert ist, weiß Ihre JPA-Implementierung, dass Sie der CHILD-Tabelle einen FK hinzufügen. Das Problem besteht darin, dass JPA bereits eine CHILD-Tabelle mit einer Spalte parent_id definiert hat.

Denken Sie daran, dass Sie ihm zwei widersprüchliche Definitionen sowohl der Funktion der Tabelle CHILD als auch der Spalte parent_id geben. In einem Fall haben Sie JPA mitgeteilt, dass es sich um eine Entität handelt und die parent_id einfach ein Wert in dieser Entität ist. Im anderen Fall haben Sie JPA mitgeteilt, dass Ihre CHILD-Tabelle keine Entität ist, sondern zum Erstellen einer Fremdschlüsselbeziehung zwischen Ihrer CHILD- und PARENT-Tabelle verwendet wird. Das Problem ist, dass Ihre CHILD-Tabelle bereits existiert. Wenn Sie dann Ihre Entität beibehalten, haben Sie ihr mitgeteilt, dass die parent_id explizit null (nicht festgelegt) ist, aber dann haben Sie ihr auch mitgeteilt, dass Ihre parent_id aktualisiert werden sollte, um eine Fremdschlüsselreferenz auf die übergeordnete Tabelle festzulegen.

Ich habe Ihren Code mit den oben beschriebenen Änderungen modifiziert und auch "persist" statt "merge" aufgerufen.

Dies führte zu 3 SQL-Abfragen

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

Dies spiegelt perfekt wider, was Sie wollen. Der PARENT-Eintrag wird erstellt. Der CHILD-Eintrag wird erstellt und dann wird der CHILD-Datensatz aktualisiert, um den Fremdschlüssel korrekt festzulegen.

Wenn Sie stattdessen die Anmerkung hinzufügen

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

Dann wird die folgende Abfrage ausgeführt, wenn das Kind eingefügt wird

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

So stellen Sie Ihren FK von Anfang an richtig ein.