微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决将现有子实体映射到新父实体时传递给持久化的分离实体

我有两个实体,如下所示。

// 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;
}

我已经有一个 Parent 对象,它有两个 Child 对象,我想将一个 Child 对象从当前的 Parent 移动到新的 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);
}

现在当我这样做时,save 方法抛出 detached entity passed to persist: Child

解决方法

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

并且您可能需要仔细检查您的级联操作。在这篇文章的末尾有更多关于这个的信息。

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

管理双向关联

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

如果您想更深入地研究关联映射,我建议您学习我的 best association mapping articles

在您的示例中,缺少 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);
}

使用级联和 orphanRemoval

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

如果您的父级有很多子级,级联删除操作可能会导致 performance issues

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。