我有以下实体:
@Entity
@Data
@Table(name = "Parents")
public class Parent {
@Id
@GeneratedValue
Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "child")
private Child child;
}
还有
@Entity
@Data
@Table(name = "Childs")
public class Child {
@Id
String number;
}
对于这两个实体,我都有一个标准的 CrudRepository。在应用程序启动时,我尝试使用以下代码填充数据库:
@Component
public class TestFiller implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
ParentRepository parentRepository;
@Autowired
ChildRepository childRepository;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
for (int i = 0; i < 100; i++) {
Parent parent = new Parent();
String childId = "CHILD" + Math.round(Math.random() * 10);
Optional<Child> childOpt = childRepository.findById(childId);
if (childOpt.isPresent()) {
parent.setChild(childOpt.get());
} else {
Child child = new Child();
child.setNumber(childId);
parent.setChild(child);
}
parentRepository.save(parent);
}
}
}
这是子存储库:
@Repository
public interface ChildRepository extends JpaRepository<Child, String> {
}
但是由于某些莫名其妙的原因,当数据库中已经存在子项时,此操作会失败:
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "childs_pkey"
Detail: Key (number)=(CHILD6) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:645) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:495) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:441) ~[postgresql-9.4-1206-jdbc42.jar:9.4]
看起来 findById 方法返回的实体几乎不受管理。为什么 Hibernate/JPA 试图保留现有实体?
编辑:根据请求我添加了 ChildRepository
最佳答案
好的,回答我自己的问题:
它是由 Parent
的 Child
属性上的 CascadeType @ManyToOne(cascade = CascadeType.ALL)
引起的。删除它即可解决问题。
显然,JPA 也将 PERSIST
操作级联到 Child,即使它可以很容易地知道 Child 已经是托管和持久实体。
关于java - Spring JPA @ManyToOne 保存因重复 key 而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49978469/