这个问题已经问了很多遍,但是我仍然找不到我的用例的解决方案:
我有一个使用Hibernate 5.x的Struts2应用程序。
该应用程序是“联系人应用程序”。它具有两个实体:一个“联系人”,可以包含零个或多个“注释”。
这是我获得联系方式:
@Override
public List<Contact> getContacts() {
//Note: Hibernate 5++ supports Java try-with-resource blocks
try (Session session = HibernateUtil.openSession()) {
List<Contact> contacts = session.createQuery("FROM Contact").list();
return contacts;
...
效果很好。直到我尝试这样的东西:
ObjectMapper mapper = new ObjectMapper();
jsonString = mapper.writeValueAsString(contacts);
错误:
16:05:16.174 [http-nio-8080-exec-2] DEBUG org.apache.struts2.dispatcher.Dispatcher - Dispatcher serviceAction failed
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.example.contactsapp.models.Contact.notes, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.example.contactsapp.models.Contact["notes"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394) ~[jackson-databind-2.10.0.jar:2.10.0]
...
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4094) ~[jackson-databind-2.10.0.jar:2.10.0]
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3404) ~[jackson-databind-2.10.0.jar:2.10.0]
at com.example.contactsapp.actions.ContactsAction.getContacts(ContactsAction.java:36) ~[classes/:?]
...
可能的解决方案
我愿意NOT想要更改为FetchType.Eager
。
由于我不使用Spring,所以不能使用@Transactional
或OpenSessionInView
。但我很想知道是否有仅适用于Hibernate的产品。
这些是我尝试过的(主要基于How to solve the “failed to lazily initialize a collection of role” Hibernate exception:]
@Override
public List<Contact> getContactsFetchAll() {
//Note: Hibernate 5++ supports Java try-with-resource blocks
try (Session session = HibernateUtil.openSession()) {
// Jackson mapper.writeValueAsString() => "failed to lazily initialize a collection"
// List<Contact> contacts = session.createQuery("FROM Contact").list();
// Plan A: Causes same "failed to lazily initialize a collection" runtime error
// List<Contact> contacts = session.createQuery("FROM Contact").list();
// Hibernate.initialize(contacts);
// Plan B: Still no-go: returns [] empty set
// List<Contact> contacts = session.createQuery("SELECT c FROM Contact c JOIN FETCH c.notes n").list();
// Plan C: Same: "failed to lazily initialize a collection of role..."
// Query query = session.createQuery("FROM Contact");
// Hibernate.initialize(query);
// List<Contact> contacts = query.list();
// Plan D: Same: "ERROR: failed to lazily initialize a collection of role"
// List<Contact> contacts = session.createQuery("FROM Contact").list();
// for (Contact c : contacts) {
// Set<Note> n = c.getNotes();
// }
return contacts;
}
}
问:有什么建议吗?
问:您需要任何其他信息吗?
如果您在实体配置中使用懒惰初始化来实现OneToMany映射,并且在某些情况下您希望尽快获取集合。我认为您可以使用@NamedQuery在单个查询中提取列表(在您的情况下为“左联接”)。