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

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

public User add(User user){ User existingUser = getUserDao().findByBusinessKey(user.getBusinessKey(), false); user.setId(existingUser.getId()); user = getUserDao().merge(user); return user; } 

我问,因为在分离的实体上显式设置ID对我来说感觉很奇怪,但即使User实体的equals和hashcode方法被适当地实现,在这里设置ID是确保合并发生的唯一方法。

有更好的做法吗?

这种方法有特殊的缺点,以后会咬我吗?

谢谢参观!

该代码将起作用 ,但不应该在分离的实体上显式设置ID。 一个典型的Hibernate应用程序有一个“保存”方法,可以处理两种情况:

  1. 用户想要创建一个新用户,因此应用程序创建一个User对象,其中“null”作为ID。
  2. 用户查询用户列表,并选择一个用于编辑。 在这种情况下,应用程序执行查询并将对象传播到“保存”方法。 该对象将具有ID,代码将向其应用新值。

看起来代码中的某些内容并没有以典型方式执行第二种情况。 如果’user’对象来自某些先前的Hibernate查询(由用户单击’edit user’或类似的东西触发),那么它将具有ID。 因此,只需要merge(user)调用。

我通常做这样的事情:

 if (user.getId() == null) em.persist(user); else user = em.merge(user); 

然后我添加代码来处理乐观锁定问题(另一个会话更新了对象)和唯一约束问题(另一个会话尝试使用相同的业务键持久化)。

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

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

 User user = userDao.findBySomething(Criteria c); //stuff that modifies user user = userDao.merge(user);