使用JSF Converter时的延迟加载异常(指一个集合)

Posted

技术标签:

【中文标题】使用JSF Converter时的延迟加载异常(指一个集合)【英文标题】:Lazy loading exception when using JSF Converter (refering to a collection) 【发布时间】:2012-04-10 19:09:57 【问题描述】:

这是我对这个问题进行多次研究后的第一篇文章。

这个例子在 Jboss 7.1 下运行,接缝 3.1(焊料 + 持久性 + 面)和接缝管理持久性上下文

在实体 bean 上使用转换器时,我遇到了一个问题,经典的 failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed。目标是通过重用 JPA 模型来保持 100% 面向对象。

在 beans.xml 中,org.jboss.seam.transaction.TransactionInterceptor 被激活

实体豆:

@Entity
public class Member implements Serializable 

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String email;

    @Column(name = "phone_number")
    private String phoneNumber;

    @ManyToMany
    private List<Statut> listeStatut = new ArrayList<Statut>();

    // getters, setters, hashcode, equals


@Entity
public class Statut implements Serializable 

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToMany(mappedBy="listeStatut")
    private List<Member> members = new ArrayList<Member>();

    // getters, setters, hashcode, equals

JSF 页面:

<h:form>
    <h:selectManyCheckbox id="stat" value="#memberModif.member.listeStatut">
        <f:converter converterId="statutConverter"/>
        <f:selectItems value="#memberModif.statutsPossibles" var="statut" itemValue="#statut" itemLabel="#statut.name" />
    </h:selectManyCheckbox>


    <h:commandLink id="register" action="#memberModif.modifier()" value="Modifier">
        <f:param name="cid" value="#javax.enterprise.context.conversation.id"/>
    </h:commandLink>
</h:form>

支持 bean(我在 SessionScoped 之后尝试使用 ConversationScoped --> 同样的问题)

@ConversationScoped
@Named
public class MemberModif implements Serializable 

    private static final long serialVersionUID = -291355942822086126L;

    @Inject
    private Logger log;

    @Inject
    private EntityManager em;

    @Inject Conversation conversation;

    private Member member;

    @SuppressWarnings("unused")
    @PostConstruct
    private void init() 
        if (conversation.isTransient()) 
            conversation.begin();
        
    

    public String modifier() 
        em.merge(member);
    

    public Member getMember() 
        if (member == null) 
            member = em.createQuery("from Member m where m.id=:id",Member.class).setParameter("id", new Long(0)).getSingleResult();
        
        return member;
    

    public List<Statut> getStatutsPossibles() 
        return em.createQuery("from Statut", Statut.class).getResultList();
    

还有转换器(受到 seam ObjectConverter 的强烈启发):

@FacesConverter("statutConverter")
public class StatutConverter implements Converter, Serializable 

    final private Map<String, Statut> converterMap = new HashMap<String, Statut>();
    final private Map<Statut, String> reverseConverterMap = new HashMap<Statut, String>();

    @Inject
    private transient Conversation conversation;

    private final transient Logger log = Logger.getLogger(StatutConverter.class);

    private int incrementor = 1;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) 
        if (this.conversation.isTransient()) 
            log.warn("Conversion attempted without a long running conversation");
        

        return this.converterMap.get(value);
    

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) 
        if (this.conversation.isTransient()) 
            log.warn("Conversion attempted without a long running conversation");
        

        if (this.reverseConverterMap.containsKey(value)) 
            return this.reverseConverterMap.get(value);
         else 
            final String incrementorStringValue = String.valueOf(this.incrementor++);
            this.converterMap.put(incrementorStringValue, (Statut)value);
            this.reverseConverterMap.put( (Statut)value, incrementorStringValue);
            return incrementorStringValue;
        
    

请注意,我把这个转换器放在这里是为了避免你在网上搜索接缝实现,但这与使用&lt;s:objectConverter/&gt;标签而不是&lt;f:converter converterId="statutConverter"/&gt;是一样的

任何帮助将不胜感激。

【问题讨论】:

好吧,看起来好像在转换器访问集合之前事务已经关闭。您确定您当时应该进行交易吗?注入的EntityManager的作用域是什么? 【参考方案1】:

您应该在同一个事务中访问对象。如果您确定您已经这样做了,您可以尝试通过在上下文中查找实体管理器而不是注入它来获取它。我有一个类似的问题,就是这样解决的。您还可以在第一次获得对它的引用时在事务中初始化集合。

Hibernate.initialize(yourCollection);  

【讨论】:

【参考方案2】:

看看这个:selectManyCheckbox LazyInitializationException on process validation

尝试: &lt;f:attribute name="collectionType" value="java.util.ArrayList" /&gt;; 在你的&lt;h:selectManyCheckbox&gt;

【讨论】:

以上是关于使用JSF Converter时的延迟加载异常(指一个集合)的主要内容,如果未能解决你的问题,请参考以下文章

具有延迟加载、过滤和排序的 jsf 数据表

如何在 JSF 上延迟 Primefaces AjaxStatus?

从Tomcat 7迁移到8时的jsf实现版本NullPointerException

Primefaces 动态列不适用于延迟加载

延迟加载和解析 PrimeFaces JavaScript 文件

升级到 jsf2 后的 ViewExpiredException