当前位置: 首页 > 知识库问答 >
问题:

spring-jpa:更新父实体不能持久化新的子实体,而是将它们解释为瞬态的

杨骏
2023-03-14

我是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);
}

现在,第二轮,我添加一个新的孩子:

@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);
}

然而,这一次的新孩子却从来没有坚持过!

通过hibernate(痛苦!)来跟踪这个,我发现了以下内容:

  • 第二次保存时,问题是第二个(新)子级。
  • 问题似乎是,当要持久化父级的子级列表时,新的子级不在EntityManager中(尚未),因此被认为是瞬态的。
  • 因此,它有效地作为空值沿链传递,导致以下结果:
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”也具有子实体的映射,这可能是相关的。该“值”是由于“瞬时”盗用而作为null传递的值。
  • 我一直在使用repository.saveandflush()来保持同步,以便调试。当我使用just.save()时,我的@PreUpdate EntityListener将被调用,但@PostUpdate侦听器从未被调用。
  • 如果只是持久化子或至少在持久化父之前给出一个Id,似乎不会有问题。但手工操作似乎也适得其反。不过,这是我能想到的唯一选择。

多谢阅读。任何帮助都将不胜感激!

共有1个答案

许照
2023-03-14

我发现了问题,尽管我还没有完全的解决方案。

首先,一些附加的背景。除了家长和孩子,我有一个相关的类,我在这里称之为“房子”。House定义了一个EntityListener,以便在保存/更新它时,创建/更新关联的父对象和子对象。因此,正是在House的PostPersist/PostUpdate期间,创建、链接、指向House,然后持久化父对象和子对象。

所以问题似乎是这是在房屋交易完成之前完成的。只需在家庭活动完成之前拔出父母/子女活动,所有的问题就会消失。

更新:

把一个归因于无知。显然,EntityCallback方法“不应该调用EntityMan-ager或Query方法,也不应该访问任何其他实体对象。”并不知道。这就提出了一个问题:我应该如何在另一个实体的活动上触发一个实体的创建。但如果有必要,我会启动另一个线程。谢谢大家!

 类似资料:
  • 我们使用JPA实体和hibernate来实现持久性。我有一个< code >计划实体和一个< code >升级实体。当我创建一个新的升级并保持它时,计划也在不知何故地得到更新。此更新导致< code > OptimisticLockException ,并阻止进一步升级。这是代码框架- 中没有映射升级。当我运行此 我在控制台日志里看到了这个 我不希望发布有关计划的更新,因为没有任何更改。我只是使用

  • 我有一个父实体a,它与映射在a_B表和a_C表中的实体B和实体C有多对多关系。在持久化时,我希望只持久化a、a_B和a_C,而不持久化B和C。如果我不使用cascadetype。all i get“object references a unsaved transient instance-save the transient instances before flush”错误。如果我使用casc

  • 控制器如下: 字典的实体如下: 和wordpair实体: java.lang.IllegalStateException:org.hibernate.transientPropertyValueException:object引用了一个未保存的瞬态实例-在刷新之前保存瞬态实例:

  • 尝试获取父实体(Msg)的实体,其中父PK (msg_id)是子实体中的FK时,尝试保持子实体(MsgRetry)时出错。 错误,如:org.hibernate.id.IdentifierGenerationException:试图从null一对一属性分配id 父实体,不需要知道子实体(至少我认为它不需要知道)。一旦子实体被持久化,我就会尝试也持久化父实体。我可以通过在子实体中没有父实体并调用关联

  • 对于新学生和新课程的情况,它工作得很好,但是在新课程和现有学生的情况下,我会从数据库中抛出一个唯一的约束冲突。关系类似于下面。 在持久化之前,我尝试使用entitymanager查找一个学生,如果该学生存在,则使用该实例而不是新的学生实例。这也不起作用,它仍然尝试执行插入而不是更新

  • 我正在尝试更新我的用户实体,我想到了一个错误:错误:NULL值违反了“id”列的Not NULL约束详细信息:失败的行包含(null,1,1) 这个问题肯定源于我在用户和配置文件之间的关系,即n-n