Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

JPA insere pai/filho resulta em MySQLIntegrityConstraintViolationException


Seu relacionamento não precisa ser bidirecional. Há algumas informações erradas nos comentários aqui.

Você também disse que adicionou o campo "parentId" na entidade Child porque assumiu que o JPA precisa "saber" sobre o campo pai para que possa definir o valor. O problema não é que o JPA não conhece o campo, com base nas anotações que você forneceu. O problema é que você forneceu "muitas" informações sobre o campo, mas essas informações não são consistentes internamente.

Altere seu campo e anotação em Pai para:
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id")
private List<Child> children;

Em seguida, remova totalmente o "parentId" da entidade Child. Você havia especificado anteriormente uma anotação JoinTable. No entanto, o que você deseja não é uma JoinTable. Uma JoinTable criaria uma terceira tabela adicional para relacionar as duas entidades entre si. O que você quer é apenas um JoinColumn. Depois de adicionar a anotação JoinColumn em um campo que também é anotado com OneToMany, sua implementação JPA saberá que você está adicionando um FK à tabela CHILD. O problema é que o JPA tem uma tabela CHILD já definida com uma coluna parent_id.

Pense que você está dando a ela duas definições conflitantes da função da tabela CHILD e da coluna parent_id. Em um caso, você disse ao JPA que é uma entidade e o parent_id é simplesmente um valor nessa entidade. No outro, você disse ao JPA que sua tabela CHILD não é uma entidade, mas é usada para criar um relacionamento de chave estrangeira entre sua tabela CHILD e PARENT. O problema é que sua tabela CHILD já existe. Então, quando você está persistindo sua entidade, você disse que o parent_id é explicitamente nulo (não definido), mas também disse que seu parent_id deve ser atualizado para definir uma referência de chave estrangeira para a tabela pai.

Modifiquei seu código com as alterações que descrevi acima e também chamei "persist" em vez de "merge".

Isso resultou em 3 consultas SQL
insert into PARENT (ID) values (default)
insert into CHILD (ID) values (default)
update CHILD set parent_id=? where ID=?

Isso reflete o que você quer perfeitamente. A entrada PAI é criada. A entrada CHILD é criada e, em seguida, o registro CHILD é atualizado para definir corretamente a chave estrangeira.

Se você adicionar a anotação
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id", nullable = false)
private List<Child> children;

Em seguida, ele executará a seguinte consulta quando inserir o filho
insert into CHILD (ID, parent_id) values (default, ?)

definindo assim seu FK corretamente desde o início.