I am writing an application with typical two objects: User and UserGroup. The latter may contain one or more instances of the former. I have the following (more / less) mapping for this:
User:
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; } }
User 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; } }
Now I have a separate DAO class for each of these objects (UserDao and UserGroupDao). All of my DAOs have EntityManager entered using the @PersistenceContext annotation, for example:
@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); } }
In this layout, I want to create a new user and assign it to an existing user group. I do it like this:
UserGroup ug = userGroupDao.findById(1); User u = new User(); u.setName("john"); u.setGroup(ug); userDao.save(u);
Unfortunately, I get the following exception:
the object refers to an unsaved transient instance - saves the transient instance before flushing: xyzmodel.User.group โ xyzmodel.UserGroup
I researched it, and I think this happens because each DAO instance has a different entityManager assigned (I checked this - the links in each DAO to the object manager are different), and the UserGroup instance passed for the entityManager user does not control.
I tried to combine the user group assigned to the user into the UserDAO object manager. There are two problems:
- It still doesn't work - the object manager wants to overwrite the existing UserGroup, and it gets an exception (obviously)
- even if it works, I would end up writing a merge code for each related object
The described case works when searching and saving are performed using the same entity manager. This indicates a question (s):
- Is my project broken? I think this is very similar to the recommended one in this answer . Should there be a single EntityManager for all DAOs (web applications otherwise)?
- Or should the assignment of the group within the DAO be done? in this case, I would finish writing a lot of code in the DAO
- Should I get rid of DAO? If so, how to handle data access correctly?
- any other solution?
I use Spring as a container and Hibernate as a JPA implementation.