0

我正在尝试从表中获取所有用户的电子邮件。实体用户:

     @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>();
          .....
     } 

在服务中,我正在获取用户并尝试查看电子邮件:

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

但我收到了下一个例外:

 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)

获取用户的方法:

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

我知道当我使用 Criteria 获取 User 时,我必须获取communicationAddresses... 怎么做?谢谢大家。

4

1 回答 1

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?

于 2013-04-19T18:45:23.003 回答