我是 Spring/JPA/Hibernate 的新手,虽然这听起来很简单,但现实并非如此。我可以使用一些帮助。
我有一个包含子实体列表的父实体。我将使用这些来简化讨论:
@Entity
public class Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="parent")
private List<Child> children= new ArrayList<Child>();
etc...
}
@Entity
public class Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
etc...
}
@Repository
public interface ParentRepository extends JpaRepository<Parent, Long> {};
第 1 轮,我创建了一个新的父级和一个新的子级,将子级添加到父级列表中,并将父级设置在子级上。当我保存父母时,孩子也被保存了。
@Transactional(propagation=Propagation.REQUIRES_NEW)
void create() {
Parent parent = new Parent();
Child child = new Child();
parent.add(child);
child.setParent(parent);
parent = repository.save(parent);
}
现在,第 2 轮,我添加了一个新孩子:
@Transactional(propagation=Propagation.REQUIRES_NEW)
void update() {
Parent parent = repository.findOne(parentID);
Child newChild = new Child();
newChild.setParent(parent);
parent.add(newChild);
parent = repository.save(parent);
}
不过,这一次新来的孩子从来没有坚持过!
我已经尝试了 CascadeType、@GeneratedValue GenerationType、@Transactional Propagation 类型的几乎所有变体......
通过休眠(痛苦!)跟踪这一点,这就是我发现的:
- 第二次保存时,问题出在第二个(新)孩子身上。
- 问题似乎是,当需要持久化父级的子级列表时,新子级不在 EntityManager 中(尚未),因此被认为是瞬态的。
- 结果,它被有效地作为 null 向下传递,导致以下结果:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing thetransaction at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) ... Caused by: javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512) ... Caused by: org.hibernate.AssertionFailure: collection [null] was not processed by flush() at org.hibernate.engine.spi.CollectionEntry.postFlush(CollectionEntry.java:225) ...
- 可能相关的是,在我的实际代码中,“Child”也有一个子实体的地图。这个“值”是由于“瞬态”盗用而作为空值传递的。
- 我一直在使用 repository.saveAndFlush() 来保持同步以进行调试。当我只使用 .save() 时,我的 @PreUpdate EntityListener 被调用,但 @PostUpdate 监听器永远不会被调用。
- 如果 Child 至少在坚持 Parent 之前被坚持或给定一个 Id,似乎不会有问题。但手动执行此操作似乎也会适得其反。不过,这是我能想到的唯一选择。
谢谢阅读。任何帮助将非常感激!