Hibernate:通过DTO中的值更新实体

时间:2016-04-21 16:51:38

标签: java hibernate jpa

我认为当我们有一个带有一些集合的实体并希望通过前端更新它时,这是非常常见的模式。

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将抛出一个“分离的实体传递给持久化”异常。

我知道两种解决方法:

  1. 不要设置id,因此孩子们每次坚持时都会得到新的ID
  2. 遍历现有子项的集合并查找相应的childDTO(具有相同的ID),然后复制值
  3. 如果你有更深层次的层次结构,第二种方法很麻烦。无论如何都要做正确的事情,即当id被设置为Child时,hibernate将会发现它实际上应该从em重新加载具有该id的Child()并使用新字段更新它。

    解决问题的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

看起来像是EntityManager::merge的完美用例:

  

将给定实体的状态合并到当前持久性中   上下文。