@ManyToMany 上的 LazyInitializationException,尽管 FetchType=EAGER

LazyInitializationException on @ManyToMany, although FetchType=EAGER

由于我仍然面临这个问题,在梳理了这个常见异常的所有解决方案之后,这是我的情况。就我而言(一个拼车),我有这两个模型:

@Entity
public abstract class Car {
    @GeneratedValue @Id
    private Long id;
    private String name;
    @ManyToMany (cascade = {CascadeType.ALL},  fetch = FetchType.EAGER) 
    @JoinTable  (name = "Car_Person", joinColumns=@JoinColumn(name = "CarId", referencedColumnName = "id"), 
             inverseJoinColumns=@JoinColumn(name = "personId", referencedColumnName = "id"))
    private List<Person> carUsers; 
    //rest omitted
}

并且:

@Entity
public class Person {
    @GeneratedValue @Id
    private Long id;
    private String name;
    private int age;
        @ManyToMany(mappedBy = "carUsers", fetch = FetchType.EAGER)
        private List<Car> cars = new ArrayList<Car>();        
        //rest omitted
}

当我像这样在我的 JSF 页面中引用 Car 时,我什至会遇到 FetchType=Fetch.EAGER 的 LazyInitializationException:

<p:selectManyMenu value="#{carController.currentCar.carUsers}" converter="personConverter">     
    <f:selectItems value="#{personBean.persons}" var="person" itemLabel="#{person.name}" itemValue="#{person}"/>        
</p:selectManyMenu>

其中 currentCar 是 Car 的子 class。

我认为,这里不需要查询,因为 JPA 正在自行解析 m:n 关系,对吗?

无论如何,我得到了这个堆栈跟踪:

11:02:27,769 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-42) org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:587)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:204)
    at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:148)
    at org.hibernate.collection.internal.PersistentBag.isEmpty(PersistentBag.java:266)
    at javax.faces.component.UIInput.isEmpty(UIInput.java:1272)
    at javax.faces.component.UIInput.validateValue(UIInput.java:1159)
    at javax.faces.component.UISelectMany.validateValue(UISelectMany.java:579)
    at javax.faces.component.UIInput.validate(UIInput.java:982)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
    at javax.faces.component.UIInput.processValidators(UIInput.java:712)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at org.primefaces.component.dialog.Dialog.processValidators(Dialog.java:423)
    at javax.faces.component.UIForm.processValidators(UIForm.java:253)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1195)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
    at io.undertow.servlet.handlers.ServletInitialHandler.access0(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:138)
    at io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:135)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction.call(ContextClassLoaderSetupAction.java:43)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.api.LegacyThreadSetupActionWrapper.call(LegacyThreadSetupActionWrapper.java:44)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
    at io.undertow.servlet.handlers.ServletInitialHandler.access[=13=]0(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:104)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
    at io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:805)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

任何帮助将不胜感激。

根据您的配置,您应该在 web.xml 中尝试将其作为 Filter 来延迟加载属性。

Hibernate(请注意您的 spring 和休眠版本以使用 org.springframework.orm.hibernate{***YOUR_VERSION***} 的正确版本):

<filter>
      <filter-name>hibernateFilter</filter-name>
      <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
      <init-param>
         <param-name>sessionFactoryBeanName</param-name>
         <param-value>sessionFactory</param-value>
      </init-param>     
   </filter>
   <filter-mapping>
     <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>

Jpa:

<filter>
    <filter-name>oemInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>oemInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>

好的,我找到了答案。感谢伟大的 BalusC.

问题不仅与多对多关系有关,这也是为什么 EAGER 抓取没有帮助,甚至反模式也没有帮助(hibernate.enable_lazy_load_no_trans,在视图中打开会话)

问题的真正原因是 SelectManyMenu。你必须告诉它,它应该处理什么样的结果集。在我的例子中,我必须像这样添加 collectionType

<p:selectManyMenu value="#carController.currentCar.motUsers}" collectionType="java.util.LinkedHashSet">