jsf-2 - 使用JSF Converter时出现懒加载异常(引用集合)

标签 jsf-2 jpa-2.0 java-ee-6 converter seam3

这是我对这个问题进行了大量研究后的第一篇文章。

此示例在 Jboss 7.1 下运行,带有 seam 3.1(焊接 + 持久性 + 面)和 seam 管理的持久性上下文

我遇到了一个问题,经典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在实体 bean 上使用转换器时。目标是通过重用 JPA 模型保持 100% 面向对象。

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

实体 bean :

@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;
        }
    }
}

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

如有任何帮助,我们将不胜感激。

最佳答案

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

Hibernate.initialize(yourCollection);  

关于jsf-2 - 使用JSF Converter时出现懒加载异常(引用集合),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9886390/

相关文章:

html - 保存后如何重置表格?

java - JBoss bean 验证需要调用 EJB

glassfish - 如何使用 CDI 将本地无状态 session Bean 注入(inject)到 JAX-RS 资源中?

regex - XPath 和正则表达式都不能在 JMeter 3.0 上运行

java - 选中复选框时如何突出显示整行

java - JPA 2 - INNER JOIN 再次调用 Query

Java EE 架构 - 在使用 JPA 2 之类的 ORM 时,是否仍然推荐使用 DAO?

security - Shiro 注释不适用于 JavaEE6 项目

java - EJB 的 CDI 注入(inject)导致 NullPointerException

jsf - JSF Beans 中的关注点分离?