0

I'm trying to get all user's emails from table. Entity user:

     @Entity
     @Table(name = "tbl_User")
     public class User {
          @Expose
          @Id
          @GeneratedValue
          @Column(name = "id")
          private Long id;
          .....
          @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
          List<CommunicationAddress> communicationAddresses = new ArrayList<CommunicationAddress>();
          .....
     } 

In the service I'm getting user and trying to look emails:

User user = userDAO.getUserById(id);
        if (user == null) {
            throw new Exception("User not found");
        } else {
            List<Email> addresses = user.getCommunicationAddresses();
        }

But I received the next exception:

 org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
        at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:137)
        at org.hibernate.collection.internal.PersistentBag.isEmpty(PersistentBag.java:249)

The method for getting user:

@Transactional
@Override
public User getUserById(Long userId) {
    Criteria criteria = sessionFactory.getCurrentSession().createCriteria(User.class);
    criteria.add(Restrictions.eq("id", userId));
    return (User) criteria.uniqueResult();
}

I understand that I must to get communicationAddresses when I get User using Criteria... How to do it? Thank's all.

blackhard
  • 502
  • 7
  • 26
  • Is the service method transactional? Is the session factory created and injected by Spring in the DAO? – JB Nizet Apr 19 '13 at 17:10
  • @JBNizet yes. The factory is injected. – blackhard Apr 19 '13 at 17:19
  • User user = userDAO.getUserById(id); After this try user = user.getId().It will load proxy object for you and then u can load addresses – Chandu Apr 19 '13 at 17:28
  • @Chandu yeah. I get user with his property, but when I try to look communicationAddresses using debug and IDEA I see next message "Method threw 'org.hibernate.LazyInitializationException' exception." – blackhard Apr 19 '13 at 17:33
  • try to load user by load() method of Hibernate. – Chandu Apr 19 '13 at 17:47
  • This link may help you..http://stackoverflow.com/questions/608947/hibernate-difference-between-session-get-and-session-load – Chandu Apr 19 '13 at 17:50
  • @Chandu Yes, load() is good variant, but I must to get the user by name and mail, too. If I'll use load(), I can to get user by id only. – blackhard Apr 19 '13 at 18:01
  • User.load(by id) will load all parameters you wanted(name and mail as well) – Chandu Apr 19 '13 at 18:05
  • @Chandu I'm fresh in Hibernate. Thanks a lot, Chandu) – blackhard Apr 19 '13 at 18:08
  • 1
    @Chandu that's not true. `load()` won't fetch lazy properties; it's even worse: It will only return a proxy (think of a completely lazy-loaded entity) which is of no use outside of the transaction (except for providing the ID). – skirsch Apr 19 '13 at 18:47

1 Answers1

6

It seems your service method is not annotated with @Transactional. Thus, after calling userDAO.getUserById(id);, there is no longer a transaction. That means that you cannot access any lazy-loaded properties of the loaded entity that hasn't been accessed/pre-fetched inside the transaction without running into a LazyInitializationException.
So you can either think about replacing LAZY with EAGER fetching (this mostly depends on the use cases you are facing) or you should annotate your Service method with @Transactional.

I'd highly suggest to annotate your service methods (instead of the DAO methods), as only there you can establish meaningful transactional boundaries when interacting with multiple entities.
Also, if you make usage of lazy loading, you must be aware of the possibility to run into that kind of exception after leaving the service layer, e.g. when rendering your view (assuming you somehow present the data).

"Prefetching' lazy associations

To trigger instant loading of lazy associations (called "dynamic association fetching"), add this line in getUserById:

criteria.setFetchMode("communicationAddresses", FetchMoode.EAGER);

However, if you do that in this specific method, I wonder why you stick to lazy loading at all?

Community
  • 1
  • 1
skirsch
  • 1,640
  • 12
  • 24
  • Thanks! I annotated my service with @Transactional and it works. But I'm interested in possibility to get the user with him addresses from DAO using Criteria. Is it possible to load full user adding any Restrictions or Expressions? – blackhard Apr 22 '13 at 08:15