0

我创建了一个作为 Web 服务 (REST) 公开的 EJB。但是,当我尝试它时,我得到了下面的异常。我将其追溯到问题实体上的 JPA 注释。@ManyToOne当我取消注释映射(具有 fetch 属性的映射)时,似乎会引发此异常。我故意将实体与其他实体之间可能存在的所有关系建立为FetchType.LAZY. 我想保持这种状态。

我正在使用容器管理的事务和所有正常的 EJB 荣耀。为什么会这样?什么是修复?

编辑: 我有一个用 注释的存储库类@Stateless,然后我在另一个 EJB 中使用这个类,它从存储库中检索问题列表。然后最后我有一个资源也用@Stateless. 是因为一些持久性上下文还是什么?

PS我已经从实体中遗漏了所有其他东西,当我按照描述修复注释时,代码可以工作。

@Entity
public class Question extends AbstractModel {

    private int id;
    private Participant participant;
    private List<Answer> answers;
    private List<QuestionCategory> categories;
    private List<QuestionFeedback> feedback;

    public Question() {
        answers = new ArrayList<Answer>();
        categories = new ArrayList<QuestionCategory>();
        feedback = new ArrayList<QuestionFeedback>();
    }

    @ManyToOne
    //@ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ParticipantId")
    public Participant getParticipant() {
        return participant;
    }

    //@OneToMany(cascade = CascadeType.ALL)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "QuestionId", nullable = false)
    public List<Answer> getAnswers() {
        return answers;
    }

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "QuestionQuestionCategory",
            joinColumns = @JoinColumn(name = "QuestionId", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "QuestionCategoryId", nullable = false)
    )
    public List<QuestionCategory> getCategories() {
        return categories;
    }

    //@OneToMany(cascade = CascadeType.ALL)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "QuestionId", nullable = false)
    public List<QuestionFeedback> getFeedback() {
        return feedback;
    }
}

抛出此异常:

[#|2012-11-11T00:10:59.182+0100|警告|glassfish3.1.2|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=71;_ThreadName=Thread-8;| StandardWrapperValve [javax.ws.rs.core.Application]:PWC1406:Servlet javax.ws.rs.core.Application 的 Servlet.service() 抛出异常 org.hibernate.LazyInitializationException:无法初始化代理 - org.hibernate 没有会话.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165) 在 org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:272) 在 org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:java:185. ) 在 sun.reflect.GeneratedMethodAccessor76.invoke(Unknown Source) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:601) 在 com.sun.xml.bind.v2.runtime.reflect.Accessor$GetterSetterReflection.get(Accessor.java:354) 在 com.sun .xml.bind.v2.runtime.reflect.Accessor.getUnadapted(Accessor.java:147) 在 com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.hasValue(TransducedAccessor.java:251) 在 com .sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:105) 在 com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:358) 在 com.sun .xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:350) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) 在 com.sun.xml.bind .v2.runtime.property.SingleElementNodeProperty。com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:358) 上的 serializeBody(SingleElementNodeProperty.java:158) com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer. java:696)在 com.sun.xml.bind.v2.runtime.property.ArrayElementNodeProperty.serializeItem(ArrayElementNodeProperty.java:69) 在 com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty. java:172) 在 com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:159) 在 com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java: 358) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593) 在 com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:340) 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494) 在 com .sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:178) 在 com.sun.jersey.json.impl.BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103) 在 com.sun.jersey.json .impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143) 在 com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:157) 在 com.sun.jersey.spi.container .ContainerResponse.write(ContainerResponse.java:306) 在 com.sun.jersey.server.impl.application.WebApplicationImpl。bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323) 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:178) 在 com.sun.jersey.json.impl。 BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103) 在 com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143) 在 com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider。 writeTo(AbstractRootElementProvider.java:157) 在 com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) 在 com.sun.jersey.server.impl.application.WebApplicationImpl。bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323) 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:178) 在 com.sun.jersey.json.impl。 BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103) 在 com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143) 在 com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider。 writeTo(AbstractRootElementProvider.java:157) 在 com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) 在 com.sun.jersey.server.impl.application.WebApplicationImpl。marshallToJSON(BaseJSONMarshaller.java:103) 在 com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143) 在 com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo( AbstractRootElementProvider.java:157) 在 com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) 在 com.sun.jersey.server.impl.application.WebApplicationImpl。marshallToJSON(BaseJSONMarshaller.java:103) 在 com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:143) 在 com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo( AbstractRootElementProvider.java:157) 在 com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) 在 com.sun.jersey.server.impl.application.WebApplicationImpl。handleRequest(WebApplicationImpl.java:1437) 在 com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349) 在 com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl. java:1339) 在 com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416) 在 com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)在 com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:770) 在 org.apache.catalina.core.StandardWrapper org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281) 处的 .service(StandardWrapper.java:1550)。_invoke(StandardContextValve.java:175) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java) 在 org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) 在 org.apache.catalina .core.StandardPipeline.invoke(StandardPipeline.java:595) 在 org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:161) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java) 在org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231) 在 com.sun.enterprise.v3.services.impl。 com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195) 上的 ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)。sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860) 在 com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757) 在 com.sun.grizzly.http.ProcessorTask.process(ProcessorTask. java:1056) 在 com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229) 在 com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) 在 com.sun.grizzly.DefaultProtocolChain.execute (DefaultProtocolChain.java:104) 在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) 在 com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) 在 com.sun.grizzly。 ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) 在 com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) 在 com.sun。com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool. java:513) 在 java.lang.Thread.run(Thread.java:722) |#]

4

2 回答 2

2

我遇到了安迪的确切问题。到目前为止我发现的是:

@ManyToOne
//@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ParticipantId")
public Participant getParticipant() {
    return participant;
}

可以设置LAZY为单个属性关联,但您不应该这样做。将@ManyToOne注释留在那里:

惰性属性获取:访问实例变量时获取属性或单值关联。这种方法需要构建时字节码检测,并且很少需要。

至于Collections我这样添加的Hibernate.initialize(categories)

有时需要在关闭 Session 之前初始化代理或集合。例如,您可以通过调用 cat.getSex() 或 cat.getKittens().size() 来强制初始化。但是,这可能会使代码的读者感到困惑,并且对于通用代码来说也不方便。静态方法 Hibernate.initialize() 和 Hibernate.isInitialized() 为应用程序提供了一种使用延迟初始化的集合或代理的便捷方式。Hibernate.initialize(cat) 将强制初始化代理 cat,只要它的 Session 仍然打开。Hibernate.initialize(cat.getKittens()) 对小猫的收集有类似的效果。

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "QuestionQuestionCategory",
        joinColumns = @JoinColumn(name = "QuestionId", nullable = false),
        inverseJoinColumns = @JoinColumn(name = "QuestionCategoryId", nullable = false)
)
public List<QuestionCategory> getCategories() {
    Hibernate.initialize(categories)
    return categories;
}

现在我有一个org.hibernate.HibernateException: collection is not associated with any session例外。根据粗体文本,会话应该是开放的。我仍然找不到在容器管理的应用程序中启动会话的方法。只是调用getCategories()不会做代理或会话初始化的伎俩。

有小费吗?

编辑:解决方案

可能您希望在用户单击某些内容然后触发动作或 actionListener 时加载关联的集合。

你需要做的是(拜托,这是非常通用的):

  • 使用该方法实现一个find(Object id)方法Hibernate.initialize()(将其从getCategories()上面代码片段中的方法中删除):

    public Question find(Object id) {
        Question question = getEntityManager().find(Question.class, id);
        Hibernate.initialize(question.getCategories());
        Hibernate.initialize(question.getAnswers());
        Hibernate.initialize(question.getFeedback());
    
        return question ;
    }
    
  • 当视图请求加载时搜索实体:

    public void userHasClickedAQuestion(Object id) {
        selectedQuestion = questionFacade.find(id);
    }
    

你完成了。当您调用 getter 方法时,您的答案、问题和反馈将被加载并显示。

于 2012-11-11T16:51:29.570 回答
0

LazyInitializationException: Session(否则:)EntityManager关闭后,其实体将被分离QuestionFeedback问题是 object (QuestionCategory和)的集合Answer是分离的。如果在 中使用lazy=false(Otherwise : FetchType.EAGER) hibernate,即使Session关闭,对象的集合也会被加载到内存中。

参考:Hibernate:理解延迟获取

于 2012-11-11T10:47:38.703 回答