我认为当我们有一个带有一些集合的实体并希望通过前端更新它时,这是非常常见的模式。
class Parent {
long id;
List<Child> childs;
}
class Child {
long id;
String property;
}
class ParentDTO {
long id;
List<ChildDTO> childs;
}
class ChildDTO {
long id;
String property;
}
现在我有一个像
这样的方法public void createOrUpdate(ParentDTO parentDTO) {
Parent parent;
if (parentDTO.id == 0L) {
parent = new Parent();
parent.childs = ChildDTO.convertToEntities(parentDTO.childs);
} else {
parent = em.find(Parent.class, parentDTO.id);
syncParent(parent, parentDTO);
}
em.saveOrUpdate(parent);
}
public static void syncParent(Parent parent, ParentDTO parentDTO) {
// this will cause issues due to setting session attached
// parent.childs collection to a new one
// parent.childs = ChildDTO.convertToEntities(parentDTO.childs);
// the better way is
parent.childs.clear();
parent.childs.addAll(ChildDTO.convertToEntities(parentDTO.childs);)
// however let's look at convert method
}
public static List<Child> convertToEntities(List<ChildDTO> childDTOs) {
//let's skip iteration
Child child = new Child();
child.id = childDTO.id;
child.property = childDTO.property;
// return childs
}
这里的问题是,如果我从ChildDTO设置一个id来尝试更新现有的Child,那么hibernate将抛出一个“分离的实体传递给持久化”异常。
我知道两种解决方法:
如果你有更深层次的层次结构,第二种方法很麻烦。无论如何都要做正确的事情,即当id被设置为Child时,hibernate将会发现它实际上应该从em重新加载具有该id的Child()并使用新字段更新它。
解决问题的正确方法是什么?