我正在编写一个具有典型两个实体的应用程序:用户和用户组。后者可能包含前者的一个或多个实例。我有以下(更多/更少)映射:
用户:
public class User {
@Id
@GeneratedValue
private long id;
@ManyToOne(cascade = {CascadeType.MERGE})
@JoinColumn(name="GROUP_ID")
private UserGroup group;
public UserGroup getGroup() {
return group;
}
public void setGroup(UserGroup group) {
this.group = group;
}
}
用户组:
public class UserGroup {
@Id
@GeneratedValue
private long id;
@OneToMany(mappedBy="group", cascade = {CascadeType.REMOVE}, targetEntity = User.class)
private Set<User> users;
public void setUsers(Set<User> users) {
this.users = users;
}
}
现在我为每个实体(UserDao 和 UserGroupDao)创建了一个单独的 DAO 类。我所有的 DAO 都使用 @PersistenceContext 注释注入(inject)了 EntityManager,如下所示:
@Transactional
public class SomeDao<T> {
private Class<T> persistentClass;
@PersistenceContext
private EntityManager em;
public T findById(long id) {
return em.find(persistentClass, id);
}
public void save(T entity) {
em.persist(entity);
}
}
使用此布局,我想创建一个新用户并将其分配给现有用户组。我这样做:
UserGroup ug = userGroupDao.findById(1);
User u = new User();
u.setName("john");
u.setGroup(ug);
userDao.save(u);
不幸的是我得到以下异常:
object references an unsaved transient instance - save the transient instance before flushing: x.y.z.model.User.group -> x.y.z.model.UserGroup
我调查了它,我认为这是因为每个 DAO 实例都分配了不同的 entityManager(我检查过 - 每个 DAO 中对实体管理器的引用是不同的)并且用户 entityManager 不管理传递了 UserGroup 实例。
我试图将分配给用户的用户组合并到 UserDAO 的实体管理器中。这有两个问题:
- 它仍然不起作用 - 实体管理器想要覆盖现有的用户组并且它得到异常(显然)
- 即使可行,我最终也会为每个相关实体编写合并代码
当查找和持久化都使用相同的实体管理器时,描述的案例有效。这指向一个问题:
- 我的设计有问题吗?我认为它与 this answer 中推荐的非常相似.所有 DAO 都应该有一个 EntityManager(网络上另有说法)吗?
- 还是应该在 DAO 内部完成组分配?在这种情况下,我最终会在 DAO 中编写大量代码
- 我应该摆脱 DAO 吗?如果是,如何很好地处理数据访问?
- 还有其他解决方案吗?
我使用 Spring 作为容器,使用 Hibernate 作为 JPA 实现。
最佳答案
EntityManager的不同实例在Spring中是正常的。它创建代理,动态使用当前在事务中的实体管理器(如果存在)。否则,将创建一个新的。
问题是您的交易太短了。检索您的用户组在事务中执行(因为 findById
方法隐式为 @Transactional
)。但是随后事务提交并且组被分离。当您保存新用户时,它会创建一个新事务,该事务失败,因为用户引用了一个分离的实体。
解决这个问题的方法(以及通常做这样的事情)是创建一个方法,在一个单个事务中完成整个操作。只需在服务类中创建该方法(任何 Spring 管理的组件都可以使用)并使用 @Transactional
对其进行注释。
关于java - 每个实体一个 DAO——如何处理引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12571194/