Java 在hibernate/jpa最佳实践问题中将分离的实体或新实体与现有实体合并

Java 在hibernate/jpa最佳实践问题中将分离的实体或新实体与现有实体合并,java,hibernate,design-patterns,jpa,persistence,Java,Hibernate,Design Patterns,Jpa,Persistence,当业务层创建一个新实体时,它在逻辑上表示应该更新的现有实体的实例(比如说它们共享相同的业务密钥),这种合并错误做法的方法是吗 public User add(User user){ User existingUser = getUserDao().findByBusinessKey(user.getBusinessKey(), false); user.setId(existingUser.getId()); user = getUserDao().merge(use

当业务层创建一个新实体时,它在逻辑上表示应该更新的现有实体的实例(比如说它们共享相同的业务密钥),这种合并错误做法的方法是吗

public User add(User user){

    User existingUser = getUserDao().findByBusinessKey(user.getBusinessKey(), false);
    user.setId(existingUser.getId());

    user = getUserDao().merge(user);

    return user;
}
我这样问是因为在分离的实体上显式地设置ID对我来说很奇怪,但是即使用户实体的equals和hashcode方法得到了适当的实现,在这里设置ID也是确保合并发生的唯一方法

有更好的做法吗

public User add(User user){

    User existingUser = getUserDao().findByBusinessKey(user.getBusinessKey(), false);
    user.setId(existingUser.getId());

    user = getUserDao().merge(user);

    return user;
}
这种方法是否有一些特定的缺点,以后会对我产生影响


谢谢你看

如果您的实体是分离的实体,那么您真正需要做的唯一一件事就是调用entityManager.merge(用户)。您不需要执行任何查找器方法。 如果您的实体不是分离的,而是新的(它没有指定id),那么在对该实体执行任何修改操作之前,您应该在数据库中找到合适的实体,然后再将其合并。i、 e:

User user = userDao.findBySomething(Criteria c);

//stuff that modifies user 

user = userDao.merge(user);
该代码将起作用,但无需在分离的实体上显式设置ID。典型的Hibernate应用程序有一个“保存”方法,可处理两种情况:

  • 用户希望创建一个新用户,因此应用程序创建了一个ID为“null”的用户对象
  • 用户查询用户列表,并正在选择一个进行编辑。在这种情况下,应用程序执行查询并将对象传播到“save”方法。对象将有一个ID,代码将对其应用新值
  • 看起来代码中的某些内容没有以典型方式执行第二种情况。如果“用户”对象来自之前的Hibernate查询(由用户单击“编辑用户”或类似的内容触发),那么它将已经有了一个ID。因此,只需要
    合并(用户)
    调用

    我通常会这样做:

    if (user.getId() == null)
      em.persist(user);
    else
      user = em.merge(user);
    
    然后,我添加代码来处理乐观锁定问题(另一个会话更新了对象)和唯一约束问题(另一个会话尝试使用相同的业务密钥持久化某些内容)


    Seam之类的框架可以使这一点更加简单,因为它们在控制器bean方法之间传播Hibernate会话。所以即使是“合并”也不需要。

    我想我的问题是你提到的第二种情况。除非在实体的新实例上显式设置id,否则合并不会成功。如果entityManager知道合并的唯一方法是使用标识符,那么这是有意义的,但我认为它应该理解.equals()。如果没有,我继续设置ID,我会遇到任何其他问题吗?equals()和hashCode()方法永远不应该假设ID已设置,它们应该始终使用业务密钥。问题在于,分离的实例不知何故没有ID(使其成为暂时的,而不是分离的)。请参阅上面的答案。我的代码段没有演示的一件事是将getUserDao()设置为原始用户引用。合并(用户)的结果。。。更新代码段以显示这一点。为什么首先要有一个ID(自动生成)和一个业务密钥?为什么不使用Busines键作为ID呢?这假设它当然永远不会改变。这一直是hibernate团队从我所读到的内容中提出的建议——在大多数情况下,除了我提出的一个问题外,它似乎效果很好:s它是否等同于无条件地
    合并
    ?除了返回对象的副本,
    merge
    可以完成
    persist
    所做的一切。IIRC,merge是persist的超集。自从我开始使用Seam以来,我几乎不再使用merge。@JoshuaDavis我很困惑,因为我曾经使用merge()作为“saveOrUpdate”,而且它很有效!!!最近,它在升级hibernate时中断了,我切换到persist(),它可以作为保存或更新,如第110行所示。(该死,我真的很喜欢saveOrUpdate)。这个平台传入UserDbo,我不在乎它是被编辑的还是全新的。我只需要调用一个saveOrUpdate方法。@DeanHiller是的。我想你看到的是“特立独行”的问题em.persist()具有JPA定义的特定行为。如果实现碰巧也做了规范没有明确禁止的事情,那么它的工作是偶然的。我更喜欢明确地说明创建vs更新,我希望ORM告诉我是否我没有做我认为我正在做的事情。