【发布时间】:2016-04-21 16:51:37
【问题描述】:
我认为当我们有一个包含一些集合的实体并希望通过前端对其进行更新时,这是很常见的模式。
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 为 Child 设置 id 并尝试更新现有的 Child - hibernate 将抛出“传递给持久化的分离实体”异常。
我知道有两种解决方法:
- 不要设置id,这样子每次持久化时都会得到新的id
- 遍历现有childs的集合,找到对应的childDTO(id相同),然后复制值
如果你有更深的层次结构,第二种方法会很麻烦。有没有办法做正确的事情,即当 id 设置为 Child 时,休眠会发现它实际上应该使用来自 em 的 id 重新加载 Child() 并使用新字段更新它。
解决问题的正确方法是什么?
【问题讨论】: