Mysql
 sql >> Base de données >  >> RDS >> Mysql

JPA insère les résultats parent/enfant dans MySQLIntegrityConstraintViolationException

Votre relation ne doit pas nécessairement être bidirectionnelle. Il y a des informations erronées dans les commentaires ici.

Vous avez également dit que vous aviez ajouté le champ "parentId" dans l'entité Child parce que vous supposiez que JPA devait "connaître" le champ parent afin de pouvoir définir la valeur. Le problème n'est pas que JPA ne connaît pas le champ, sur la base des annotations que vous avez fournies. Le problème est que vous avez fourni "trop" d'informations sur le champ, mais ces informations ne sont pas cohérentes en interne.

Remplacez votre champ et votre annotation dans Parent par :

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

Supprimez ensuite entièrement le "parentId" de l'entité enfant. Vous aviez précédemment spécifié une annotation JoinTable. Cependant, ce que vous voulez n'est pas un JoinTable. Un JoinTable créerait une troisième table supplémentaire afin de relier les deux entités l'une à l'autre. Ce que vous voulez n'est qu'un JoinColumn. Une fois que vous avez ajouté l'annotation JoinColumn sur un champ qui est également annoté avec OneToMany, votre implémentation JPA saura que vous ajoutez un FK dans la table CHILD. Le problème est que JPA a une table CHILD déjà définie avec une colonne parent_id.

Pensez-y que vous lui donnez deux définitions contradictoires de la fonction de la table CHILD et de la colonne parent_id. Dans un cas, vous avez dit à JPA qu'il s'agit d'une entité et que le parent_id est simplement une valeur dans cette entité. Dans l'autre, vous avez indiqué à JPA que votre table CHILD n'est pas une entité, mais est utilisée pour créer une relation de clé étrangère entre votre table CHILD et PARENT. Le problème est que votre table CHILD existe déjà. Ensuite, lorsque vous conservez votre entité, vous lui avez dit que le parent_id est explicitement nul (non défini), mais vous lui avez également dit que votre parent_id doit être mis à jour pour définir une référence de clé étrangère à la table parent.

J'ai modifié votre code avec les changements que j'ai décrits ci-dessus, et j'ai aussi appelé "persist" au lieu de "merge".

Cela a entraîné 3 requêtes SQL

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

Cela reflète parfaitement ce que vous voulez. L'entrée PARENT est créée. L'entrée CHILD est créée, puis l'enregistrement CHILD est mis à jour pour définir correctement la clé étrangère.

Si vous ajoutez plutôt l'annotation

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

Ensuite, il exécutera la requête suivante lors de l'insertion de l'enfant

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

réglant ainsi votre FK correctement dès le début.