Hibernate &引用;无法初始化代理-无会话“;有一个开放的会议

Hibernate &引用;无法初始化代理-无会话“;有一个开放的会议,hibernate,jsf,jpa,cdi,myfaces,Hibernate,Jsf,Jpa,Cdi,Myfaces,我使用JSF2(MyFaces2.1.7和PrimeFaces3.4.2)、CDI(Weld servlet 1.1.10)、JPA2(Hibernate 4.1.7)和Lombok 0.11.2。所有这些都在Tomcat6和7上运行 我使用通过过滤器实现的模式 @Advanced @Data @Slf4j public class TransactionalFilter implements Filter, Serializable { private static final lo

我使用JSF2(MyFaces2.1.7和PrimeFaces3.4.2)、CDI(Weld servlet 1.1.10)、JPA2(Hibernate 4.1.7)和Lombok 0.11.2。所有这些都在Tomcat6和7上运行

我使用通过
过滤器实现的模式

@Advanced
@Data
@Slf4j
public class TransactionalFilter implements Filter, Serializable {

    private static final long serialVersionUID = 999173590695648899L;

    @Inject
    private EntityManager em;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        boolean newTransaction = false;
        EntityTransaction tx = em.getTransaction();
        if (!tx.isActive()) {
            tx.begin();
            newTransaction = true;
        }

        try {
            chain.doFilter(request, response);
            if (newTransaction && tx.isActive()) {
                tx.commit();
            }
        } catch (Exception e) {
            if (newTransaction && tx.isActive()) {
                tx.rollback();
            }
            throw new ServletException(e);
        }

    }
    (...)
}
注入的
RequestScoped
EntityManager
由my
EntityManager工厂提供,该工厂也为我的所有服务提供了它

@ApplicationScoped
@Data
@Slf4j
public class TransactionalEntityManagerFactory implements Serializable {

    private static final String PU_NAME = "fr.senat.dosleg";
    private static final long serialVersionUID = -3595175390458199193L;
    private EntityManagerFactory emf;

    /** (...)
     * @return un nouvel EntityManager.
     */
    @Produces
    @RequestScoped
    public EntityManager getEntityManager() {
        if (emf == null) {
            emf = Persistence.createEntityManagerFactory(PU_NAME);
        }
        return emf.createEntityManager();
    }

    /**(...)
     * @param em le gestionnaire d'entité à libérer.
     */
    public void closeEntityManager(@Disposes EntityManager em) {
        if (em != null && em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }

        if (em != null && em.isOpen()) {
            em.close();
        }
    }
}
这一切都很好,直到我添加了下面Controle实体中显示的
列表

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude = { "organisme", "groupePolitique", "lois", "livrables",
    "acteurs", "themes" })
public class Controle implements Serializable {

    private static final long serialVersionUID = -6471695606036735891L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @NotNull
    @Size(max = 256, message = "trop long.")
    private String libelle;

    @Pattern(regexp = Constants.URL_PATTERN, message = "pas au bon format")
    private String url;

    @NotNull
    @Type(type = "fr.senat.util.hibernate.usertype.OuiNonSmallType")
    private boolean initiativeDesGroupes;

    @NotNull
    @Type(type = "fr.senat.util.hibernate.usertype.OuiNonSmallType")
    private boolean courDesComptes;

    @NotNull
    private int anneeCreation;

    @Embedded
    private EcheanceControle echeance = new EcheanceControle();

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "ORGCOD")
    private Organisme organisme;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "GRPPOL")
    private GroupePolitique groupePolitique;

    @ManyToMany
    @JoinTable(name = "CONTROLE_LOI", joinColumns = @JoinColumn(name = "CON_ID"), inverseJoinColumns = @JoinColumn(name = "LOICOD"))
    private List<Loi> lois;

    @OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
    @JoinColumn(name = "CON_ID", nullable = false)
    private List<LivrableControle> livrables;

    @OneToMany(orphanRemoval = true, cascade = CascadeType.ALL)
    @JoinColumn(name = "CON_ID", nullable = false)
    private List<ActeurControle> acteurs;

    @ManyToMany
    @JoinTable(name = "THEME_CONTROLE", joinColumns = @JoinColumn(name = "CON_ID"), inverseJoinColumns = @JoinColumn(name = "THECLE"))
    private List<Theme> themes;

    (...)

}
这就是错误所在

<?xml version="1.0" encoding="utf-8"?>
<partial-response>
    <error>
        <error-name>org.hibernate.LazyInitializationException</error-name>
        <error-message><![CDATA[could not initialize proxy - no Session]]></error-message>
    </error>
</partial-response>
如果有人想试一试,这里有一些来自该方法调试的提示

  • classmodeltype=expression.getType(facesContext.getELContext())
    java.util.List
  • Collection.class.isAssignableFrom(modelType)
    为true
  • collectionTypeAttr!=null
    为false
  • Collection.class.isAssignableFrom(modelType)
    为true
  • Collection componentValue=(Collection)component.getValue()
    是一个
    PersistenBag
    ,它似乎使用数据(
    storedSnapshot
    角色
    )正确初始化,但具有空的
    会话
  • targetForConvertedValues=(componentValue!=null?componentValue.getClass():modelType).newInstance()
    最终成为一个
    持久包
    ,所有内容都为空(包括数据)。这可能是问题所在吗
  • boolean isArray=(targetForConvertedValues.getClass().isArray())为false
  • ((集合)targetForConvertedValues)。添加(值)是一切都出错的地方

  • 有什么想法吗?

    当您从数据库接收到包含集合的对象时,默认情况下,Hibernate中的集合是延迟加载的,而不是列表或集合,该列表或集合有一个代理。调用该集合的getter方法后,将获取该集合。但是,如果对象所源自的会话已关闭或不再可访问(不应在OpenSessionInView筛选器的约束范围内),则会出现问题

    如果对象由不同的会话处理,您可以尝试调用
    session.merge
    。或者,您可以在获取期间手动调用列表的
    getter
    ,这将触发代理。或者,您可以在集合中添加
    FetchType.Eager
    ,在这种情况下,即使在提取时,对象也不会是代理,而是真实的对象

    但我看到您正在使用Weld进行CDI,为什么不使用支持事务管理的Seam持久化模块呢?然后,您将能够非常快速地实现视图中的开放会话方法


    在我看来,这是我在Mojarra发现的一个非常讨厌的bug,在这个版本的MyFaces中可能也是如此。最基本的是,当它进行验证时,它会复制列表,但它使用集合的具体类型,使用无参数构造函数来创建集合。在hibernate的例子中,这个新列表没有运行所有的init代码,也没有链接回会话。我花了很长时间调试Mojarra源代码,以了解到底发生了什么


    我发现我必须使用collectionType属性并将其设置为java.util接口类型。在没有明确告诉JSF要使用的集合类型的情况下,我不再处理集合

    默认情况下,您的集合是延迟加载的。如果您试图在会话上下文之外访问列表,但代理未加载,它将发出抱怨,因为代理对象无法再访问其会话。如果您认为对象来自另一个会话,请尝试session.merge将对象合并到当前会话。或者,如果您愿意,可以在您的集合中添加eager,尽管在大多数情况下并不需要它。如StackTrace所示,异常发生在验证期间,在实际进入我的Bean代码之前。因此,我不知道在哪里添加手动合并的“hack”。FetchType。如问题中所述,我已经尝试过了。这并不能改变问题。我可能会查看PersistenceModule,但我认为对于我需要的简单的东西来说,它可能有点“大”。谢谢您的回复。我不相信这是解决方案,因为提供的stacktrace表明异常发生在PersistentBag内部,我认为如果Hibernate没有意识到这是一个代理,则不会发生这种情况。但是,我尝试将
    @CollectionType(type=“java.util.List”)
    添加到我的
    私有列表主题中我得到了一个
    自定义类型没有实现UserCollectionType:java.util.List
    :也许我还不明白你的建议是什么?我最初也这么认为。就像我说的,花了很长时间才发现(浪费了一整天)试一下,这是一个小小的改变。如果它不起作用,那么你知道什么是不起作用的。它在视图中,而不是实体中。它位于多个选定组件上。感谢您的跟进。我想尝试一下您的建议,但在
    中、PrimeFaces参考资料中或互联网上找不到有关
    collectionType
    属性的任何信息。可以更具体一点吗?它是基类上的标准jsf属性。下面是一些描述问题或属性的其他链接:最后,我实际上必须将
    collectionType
    设置为实际实现
    ArrayList
    ,而不是接口。我还必须确保我的转换器在那里。现在它开始工作了。这难道不能被认为是myfaces或primefaces上的一个bug,或者这是正常的吗?
    <?xml version="1.0" encoding="utf-8"?>
    <partial-response>
        <error>
            <error-name>org.hibernate.LazyInitializationException</error-name>
            <error-message><![CDATA[could not initialize proxy - no Session]]></error-message>
        </error>
    </partial-response>
    
    PersistentBag(AbstractPersistentCollection).withTemporarySessionIfNeeded(LazyInitializationWork<T>) line: 180   
    PersistentBag(AbstractPersistentCollection).initialize(boolean) line: 520   
    PersistentBag(AbstractPersistentCollection).write() line: 345   
    PersistentBag.add(Object) line: 291 
    _SharedRendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, String[], boolean) line: 339 
    RendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, Object, boolean) line: 1088 
    RendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, Object) line: 1056  
    HtmlCheckboxRenderer(HtmlCheckboxRendererBase).getConvertedValue(FacesContext, UIComponent, Object) line: 525   
    SelectManyButtonRenderer.getConvertedValue(FacesContext, UIComponent, Object) line: 36  
    SelectManyButton(UISelectMany).getConvertedValue(FacesContext, Object) line: 402    
    SelectManyButton(UIInput).validate(FacesContext) line: 584  
    SelectManyButton(UISelectMany).validate(FacesContext) line: 393 
    SelectManyButton(UIInput).processValidators(FacesContext) line: 274 
    HtmlPanelGrid(UIComponentBase).processValidators(FacesContext) line: 1421   
    Panel(UIComponentBase).processValidators(FacesContext) line: 1421   
    Panel.processValidators(FacesContext) line: 297 
    HtmlForm(UIForm).processValidators(FacesContext) line: 209  
    HtmlBody(UIComponentBase).processValidators(FacesContext) line: 1421    
    UIViewRoot(UIComponentBase).processValidators(FacesContext) line: 1421  
    UIViewRoot._processValidatorsDefault(FacesContext) line: 1401   
    UIViewRoot.access$500(UIViewRoot, FacesContext) line: 74    
    UIViewRoot$ProcessValidatorPhaseProcessor.process(FacesContext, UIViewRoot) line: 1508  
    UIViewRoot._process(FacesContext, PhaseId, UIViewRoot$PhaseProcessor) line: 1357    
    UIViewRoot.processValidators(FacesContext) line: 799    
    ProcessValidationsExecutor.execute(FacesContext) line: 38   
    LifecycleImpl.executePhase(FacesContext, PhaseExecutor, PhaseListenerManager) line: 170 
    LifecycleImpl.execute(FacesContext) line: 117   
    CodiLifecycleWrapper.execute(FacesContext) line: 95 
    FacesServlet.service(ServletRequest, ServletResponse) line: 197 
    ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 290  
    ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206  
    PrettyFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 145   
    ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235  
    ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206  
    ApplicationDispatcher.invoke(ServletRequest, ServletResponse, ApplicationDispatcher$State) line: 646    
    ApplicationDispatcher.processRequest(ServletRequest, ServletResponse, ApplicationDispatcher$State) line: 436    
    ApplicationDispatcher.doForward(ServletRequest, ServletResponse) line: 374  
    ApplicationDispatcher.forward(ServletRequest, ServletResponse) line: 302    
    PrettyFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 137   
    ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235  
    ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206  
    TransactionalFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 60 
    ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235  
    ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206  
    SetUtf8CharacterEncodingFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 44  
    (...)
    Thread.run() line: 662  
    
    _SharedRendererUtils.getConvertedUISelectManyValue(FacesContext, UISelectMany, String[], boolean) (line 143)