将现有子实体映射到新父实体时传递以持久化的分离实体

Chi*_*dia 1 java hibernate spring-data-jpa

I have two entity as below.

// Parent entity
class Parent {
 @OneToMany(mappedBy = "parent", orphanRemove=true, cascade=CascadeType.ALL)
 Set<Child> children;
}

// Child entity
class Child {
  @ManyToOne(cascade={CascadeType.MERGE, CascadeType.PERSIST})
  Parent parent;
}
Run Code Online (Sandbox Code Playgroud)

I already have one Parent object which has two Child object and I want to move one Child object from current Parent to new Parent.

@Transactional
public void mapChildToNewParent() {
    // Get existing child and remove it from existing parent
    Parent existingParent = parentRepo.findById(1L);
    Child existingChild = existingParent.getChildren().iterator().next();
    existingParent.remove(existingChild);

    // Create new parent and add existingChild in it
    Parent newParent = new Parent();
    Set<Child> childrens = new HashSet<Child>();
    childrens.add(existingChild);
    newParent.setChildren(childrens)

    // Save modified parent entities
    parentRepo.save(existingParent);
    parentRepo.save(newParent);
}
Run Code Online (Sandbox Code Playgroud)

Now when I do this, save method throws detached entity passed to persist: Child

Tho*_*sen 5

您的代码中缺少一个基本步骤:您需要更新协会的拥有方。缺少它可能会导致此类异常或阻止 Hibernate 对数据库执行任何更新。

您可能需要仔细检查您的级联操作。有关更多信息,请参阅本文末尾。

免责声明:我无法在示例项目中重现错误消息。Hibernate 没有出现错误,而是悄悄地从数据库中删除了子记录。但这可能是一个取决于 Hibernate 版本和/或周围代码的细节。

管理双向关联

让我们从最重要的部分开始:您建模了一个双向关联。当你在业务代码中使用它时,你总是需要更新两边。

如果您想更深入地研究关联映射,我建议您学习我最好的关联映射文章。

child.setParent(newParent)在您的示例中,缺少该方法的调用:

@Transactional
public void mapChildToNewParent() {
    // Get existing child and remove it from existing parent
    Parent existingParent = parentRepo.findById(1L);
    Child existingChild = existingParent.getChildren().iterator().next();
    existingParent.remove(existingChild);

    // Create new parent and add existingChild in it
    Parent newParent = new Parent();
    Set<Child> childrens = new HashSet<Child>();
    childrens.add(existingChild);
    newParent.setChildren(childrens)

    child.setParent(existingChild);

    // Save modified parent entities
    parentRepo.save(existingParent);
    parentRepo.save(newParent);
}
Run Code Online (Sandbox Code Playgroud)

使用级联和孤儿移除

您在映射中使用级联和孤儿删除。这些只能用于子级依赖于父级的纯父子关联。在这些情况下,在关联的两端都具有级联定义的情况并不常见。您应该仔细检查是否需要Child.parent属性上的级联定义以及它是否提供了预期的结果。

如果您的父级有很多子级,级联删除操作可能会导致性能问题。