Reputation: 1375
I have some model classes with relations to each other (User
, Group
, Message
, etc). For many reasons (I'm not giving the details, but this is not a flexible decision) the relations are Lazy, and I want them to remain Lazy.
Sometimes I want to load some class collections. P.e. user.getGroups()
or user.getMessages()
but, because of the Lazy load, I need to call Hibernate.initialize()
in the method of the DAO class, which is OK for me.
The question is, Is there a strategy to avoid declaring many DAO methods to load several combination of collections, reusing the methods?
Here is an example of what I want to avoid:
UserController:
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/user/view/{id}", method = RequestMethod.GET)
public String view(@PathVariable Long id, Model model) {
// Choose one between the following, depending on the case
User user = userService.getUser(id);
User user = userService.getUserWithGroups(id);
User user = userService.getUserWithGroupsAndMessages(id);
//...
}
}
And the UserDAOImpl:
@Repository
public class UserDAOImpl implements UserDAO {
@Override
public User getUser(long id) {
return (User) this.getCurrentSession().get(User.class, id);
}
@Override
public User getUserWithGroups(long id) {
User user = (User) this.getCurrentSession().get(User.class, id);
Hibernate.initialize(user.getGroups());
return user;
}
@Override
public User getUserWithGroupsAndMessages(long id) {
User user = (User) this.getCurrentSession().get(User.class, id);
Hibernate.initialize(user.getGroups());
Hibernate.initialize(user.getMessages());
return user;
}
}
The point is I want to avoid creating multiple DAO methods for each combination of collections that must be loaded for each case. I'd like to achieve a call syntaxis in the Controller similar to User user = userService.getUser(id).initGroups().initMessages();
, to chain only the specific methods I need in every case.
But in this particular example, the initXXX()
methods would be in the model class User
, which may not contain any @Autowired service
, and because of that is not a possible solution.
Any ideas?
--EDIT--
Some non-working ideas:
Option 1. Declare initGroups()
in User
model class:
User
@Entity
@Table(name="user")
public class User implements Serializable {
//...
public User initGroups() {
Hibernate.initialize(getGroups());
return this;
}
}
Called from Controller this way: User user = userService.getUser(id).initGroups();
Option 2. Declare initGroups()
in UserService
and UserDAO
:
UserServiceImpl
@Service
@Transactional
public class UserServiceImpl implements UserService {
//...
@Override
public User initGrupos(User user) {
return userDAO.initGroups(user);
}
}
UserDAOImpl
@Repository
public class UserDAOImpl implements UserDAO {
//...
@Override
public User initGroups(User user) {
Hibernate.initialize(user.getGroups());
return user;
}
}
Called from Controller this way:
User user = userService.getUser(id);
user = userService.initGroups(user);
Result (both the same):
org.hibernate.HibernateException: collection is not associated with any session
org.hibernate.collection.internal.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:484)
org.hibernate.Hibernate.initialize(Hibernate.java:78)
...
Upvotes: 2
Views: 948
Reputation: 44545
The init methods don't need the service, they just need to call Hibernate.initialize while maintaining the previous Hibernate session which loaded the object in the first place (that is the most important part).
Upvotes: 2