我有一个Java API(使用Spring框架),前端使用它来创建新的父对象(json),其中包含一个新的子对象列表,如下所示:
parent = {
children: [
{
childName: 'name1'
},
{
childName: 'name2'
}]
}
您会看到那里没有ID,因为我要保存它们,因此数据库应该生成ID。
父级实体在后端中具有以下代码:
@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "parent")
private Set<Child> children = new HashSet<>();
在父级上调用存储库的“保存”操作后,我可以在数据库中找到子级元素(因此级联工作),但是数据库中子级的“ parentId”列为空,因此当我获取父级,其子级列表显示为空。
我可以通过在服务类中执行以下操作来解决此问题:
repository.save(parent);
parent.getChildren().forEach((child) -> child.setParent(parent));
,它之所以有效,是因为(到时候为止)父数据库已经为数据库生成了一个ID,因此子表可以将该ID用于其parentId列。它可以工作,但是感觉应该是标准的一对多关系,并且应该由框架以比这更漂亮的方式自动处理。所以我的问题是:我想念什么?
在级联操作期间保存时,Hibernate是否有某种方式可以自动填充子实体的“ parentId”列?
编辑: 实际上,这可能是由我用来将DTO映射到POJO并返回的MapStruct引起的。尚不确定,但会继续调查(请参阅相关链接:https://github.com/mapstruct/mapstruct/issues/1068)
答案 0 :(得分:0)
以下是有关如何创建实体和添加子代的一些基础知识。如您所见,您将不必遍历子级并在那里设置父级的引用。
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以正确设置引用。希望对您有所帮助。
答案 1 :(得分:0)
我知道了,对不起,这确实不是Hibernate的问题。
问题是我使用MapStruct来使用更简单的前端对象。这将对象分为POJO和它们各自的DTO对象。 DTO对象没有对整个其他对象的引用,它们只是复制了一些更相关的部分以简化json。
例如,ChildDTO仅具有
{
name : 'name',
parentId: '1'
}
,然后在从前端到后端进行调用时使用MapStruct,将DTO转换为真实的Java对象,在数据库(“ ish”)中按ID查找父对象,并将其添加到子对象中。但是默认情况下,它不知道将父引用添加到未设置parentId的子元素中,即使它们作为父元素的一部分而出现()>(!)。因此,在Java Child类中-父引用为null。
至少有两种解决方案:
MapStruct解决方案:
向MapStruct映射器添加自定义映射代码,以手动设置作为父级一部分发送的所有子元素的父级引用。参见here
Java解决方案:
在MapStruct运行后但保存到数据库之前,将父级引用手动添加到所有子级:
// MapStruct first maps the DTO to a real Parent object, then:
parent.getChildren().forEach((child) -> child.setParent(parent));
parentRepository.save(parent);
答案 2 :(得分:0)
很棒的解决方案-几天来一直遇到相同的问题,我有一个层叠的oneToOne,oneToMany等,设置生成一个相当广泛的xml。我仍然必须在父级上添加级联。
GrandParent finalGrandParent = grandparent;
grandparent.getParent().getChildren().forEach(child -> child.setParent(finalGrandParent.getParent()));