Hibernate 级联一对多未正确连接 child 与 parent

Hibernate cascade One to Many doesn't connect child with parent properly

我有一个 Java API(使用 Spring 框架),我的 front-end 使用它来创建新的 parent objects (json) 其中有一个新的 child objects 列表,如下所示:

parent = {
    children: [
    {
        childName: 'name1'
    },
    {
        childName: 'name2'
    }]   
}

如您所见,那里没有 ID,因为我要保存它们,数据库应该会生成 ID。

Parent 实体在后端有此代码:

@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "parent")
private Set<Child> children = new HashSet<>();

在 Parent 上调用存储库 'save' 操作后,我可以在数据库中找到 Child 元素(所以级联有效),但是 'parentId' 列数据库中的 child 为空,因此当我获取 parent 时,它的 children 列表显示为空。

我可以通过在我的服务中做这样的事情来解决这个问题 class:

repository.save(parent);
parent.getChildren().forEach((child) -> child.setParent(parent));

之所以有效,是因为(我猜)到那时 parent 已经由数据库为它生成了一个 ID,因此 child table 可以使用该 ID它的 parentId 列。它有效,但感觉这应该是一个标准的 One-to-many 关系,并且应该由框架以比这更漂亮的方式自动处理。所以我的问题是:我错过了什么?

在级联操作期间保存 child 实体 'parentId' 列时,Hibernate 是否可以通过某种方式自动填充它们?

编辑: 这实际上可能是由我用来将 DTO 映射到 POJO 并返回的 MapStruct 引起的。还不确定,但会继续调查(参见相关 link:https://github.com/mapstruct/mapstruct/issues/1068

以下是有关如何创建实体和添加子实体的一些基础知识。正如您将看到的,您将不必遍历子项并在那里设置父项的引用。

public class Parent implements Serializable {
    //bi-directional many-to-one association to Children
    @OneToMany(mappedBy="Parent")
    private List<Children> children;

    public List<Children> getChildren() {
        return children;
    }

    public void setChildren(List<Children> children) {
        this.children= children;
    }

    public Children addChildren(Children child) {
        getChildren().add(child);
        child.setParent(this);

        return child;
    }

    public Children removeChildren(Children child) {
        getChildren().remove(child);
        child.setParent(null);

        return child;
    }
}

现在创建父对象并调用 addChildren 正确设置引用。希望对你有帮助。

我弄明白了,这真的不是 Hibernate 问题,抱歉。

问题是我使用 MapStruct 来处理更简单的 front-end objects。这将 objects 分成 POJO 和它们各自的 DTO object。 DTO object 没有对整个其他 object 的引用,它们只是将一些更相关的部分复制到其中以使 json 更简单。

所以Child例如DTO只有

{ 
    name : 'name',
    parentId: '1'
}

然后当调用来自front-end到后端时使用MapStruct,将DTO转换为真正的Java object,通过id找到parent数据库 ('ish'),并将其添加到 child。但默认情况下,它不知道将 parent 引用添加到 child 没有设置 parentId 的元素, 即使它们作为parent (!)。因此,在 Java Child class - parent 引用为空。

至少有两种解法:

MapStruct解决方案:

将自定义映射代码添加到 MapStruct 映射器以手动设置作为 parent 的一部分发送的所有 child 元素的 parent 引用。参见 here

Java解法:

在 MapStruct 具有 运行 之后,但在保存到数据库之前,手动添加对所有 children 的 parent 引用:

// MapStruct first maps the DTO to a real Parent object, then:
parent.getChildren().forEach((child) -> child.setParent(parent));
parentRepository.save(parent);

很好的解决方案 - 几天来一直遇到同样的问题,我有一个级联的 oneToOne、oneToMany 等,设置生成相当广泛的 xml。我仍然必须向父级添加级联。

GrandParent finalGrandParent = grandparent;
grandparent.getParent().getChildren().forEach(child -> child.setParent(finalGrandParent.getParent()));