我有以下实体:
@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);
}
}
}
这是ChildRepository:
@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
答案 0 :(得分:0)
我认为这是因为你的String ID。 你可以尝试用findOne()方法来帮助你。
String childId = "CHILD" + Math.round(Math.random() * 10);
Child child = new Child();
child.setNumber(childId);
Child childOpt = childRepository.findOne(child);
答案 1 :(得分:0)
这是一个基于价值的课程;使用身份敏感操作 (包括引用相等(==),标识哈希码或 可选的实例可能具有不可预测性 结果,应该避免。
所以首先尝试从结果中获取对象并检查它是否是预期值: -
if (childOpt.isPresent()) {
Child checkObj=childOpt.get():
parent.setChild(checkObj);
}
答案 2 :(得分:0)
好的,回答我自己的问题:
它是由@ManyToOne(cascade = CascadeType.ALL)
的{{1}}属性上的CascadeType Child
引起的。删除它修复了它。
显然,JPA也会将Parent
操作级联到Child,即使它很容易知道Child已经是托管和持久化实体。