com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel 处的 org.hibernate.LazyInitializationException [英] org.hibernate.LazyInitializationException at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel

查看:18
本文介绍了com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel 处的 org.hibernate.LazyInitializationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管有 FetchType.EAGERJOIN FETCH,但在将一些对象添加到 @ManyToMany 时,我得到了一个 LazyInitalizationExceptioncode> 通过 JSF UISelectMany 组件收集,例如在我的例子中是 .

Despite of FetchType.EAGER and JOIN FETCH, I get a LazyInitalizationException while adding some objects to a @ManyToMany collection via a JSF UISelectMany component such as in my case the <p:selectManyMenu>.

@Entity IdentUser,带有 FetchType.EAGER:

@Column(name = "EMPLOYERS")
@ManyToMany(fetch = FetchType.EAGER, cascade= CascadeType.ALL)
@JoinTable(name = "USER_COMPANY", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "COMPANY_ID") })
private Set<Company> employers = new HashSet<Company>();

@Entity Company,带有 FetchType.EAGER:

@ManyToMany(mappedBy="employers", fetch=FetchType.EAGER)
private List<IdentUser> employee;

JPQL,带有JOIN FETCH:

public List<IdentUser> getAllUsers() {
    return this.em.createQuery("from IdentUser u LEFT JOIN FETCH u.employers WHERE u.enabled = 1 AND u.accountNonLocked=0 ").getResultList();
}

JSF UISelectMany 组件在提交时导致异常:

The JSF UISelectMany component causing the exception while submitting:

<p:selectManyMenu value="#{bean.user.employers}" converter="#{entityConverter}">
    <f:selectItems value="#{bean.companies}" var="company" itemValue="#{company}" itemLabel="#{company.name}"/>
</p:selectManyMenu>

堆栈跟踪的相关部分:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
    at org.hibernate.collection.internal.PersistentSet.add(PersistentSet.java:206)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel(MenuRenderer.java:382)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValue(MenuRenderer.java:129)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:315)
    at org.primefaces.component.selectmanymenu.SelectManyMenuRenderer.getConvertedValue(SelectManyMenuRenderer.java:37)
    ...

这是怎么引起的,我该如何解决?

How is this caused and how can I solve it?

推荐答案

在提交时,JSF UISelectMany 组件需要使用提交和转换的值预填充.它不会清除并重用模型中的现有集合,因为这可能会反映在对同一集合的其他引用中,或者可能因 UnsupportedOperationException 而失败,因为该集合是不可修改的,例如通过 Arrays#asList()Collections#unmodifiableList() 获得的.

While submitting, the JSF UISelectMany components need to create a brand new instance of the collection with the submitted and converted values prefilled. It won't clear out and reuse the existing collection in the model as that may either get reflected in other references to the same collection, or may fail with an UnsupportedOperationException because the collection is unmodifiable, such as the ones obtained by Arrays#asList() or Collections#unmodifiableList().

MenuRendererUISelectMany(和 UISelectOne) 负责这一切的组件,将默认创建一个基于集合的全新实例集合的 getClass().newInstance().如果 getClass() 返回 Hibernate 的 PersistentCollection,Hibernate 内部使用它来填充实体的集合属性.add() 方法即需要通过当前会话初始化底层代理,但没有,因为作业不是在事务服务方法中执行的.

The MenuRenderer, the renderer behind UISelectMany (and UISelectOne) components who's responsible for this all, will by default create a brand new instance of the collection based on collection's getClass().newInstance(). This would in turn fail with LazyInitializationException if the getClass() returns an implementation of Hibernate's PersistentCollection which is internally used by Hibernate to fill the collection property of an entity. The add() method namely needs to initialize the underlying proxy via the current session, but there's none because the job isn't performed within a transactional service method.

要覆盖 MenuRenderer 的默认行为,您需要通过 collectionType 属性明确指定所需集合类型的 FQNUISelectMany 组件.对于 List 属性,您希望指定 java.util.ArrayList,对于 Set 属性,您希望指定 java.util.LinkedHashSet(或 java.util.HashSet 如果排序不重要):

To override this default behavior of MenuRenderer, you need to explicitly specify the FQN of the desired collection type via the collectionType attribute of the UISelectMany component. For a List property, you'd like to specify java.util.ArrayList and for a Set property, you'd like to specify java.util.LinkedHashSet (or java.util.HashSet if ordering isn't important):

<p:selectManyMenu ... collectionType="java.util.LinkedHashSet">

这同样适用于所有其他 UISelectMany 组件,它们直接绑定到 Hibernate 管理的 JPA 实体.例如:

The same applies to all other UISelectMany components as well which are directly tied to a Hibernate-managed JPA entity. E.g:

<p:selectManyCheckbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyCheckbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyListbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyMenu ... collectionType="java.util.LinkedHashSet">

另见 VDL其中包括 的文档.不幸的是,这在 < 的 VDL 文档中没有指定;p:selectManyMenu>,但由于它们使用相同的渲染器进行转换,因此它必须工作.如果 IDE 对未知的 collectionType 属性大惊小怪,并且烦人地强调它,即使它在您忽略'n'运行它时也能工作,那么请改用 <f:attribute>.

See also the VDL documentation of among others <h:selectManyMenu>. This is unfortunately not specified in VDL documentation of <p:selectManyMenu>, but as they use the same renderer for converting, it must work. If the IDE is jerking about an unknown collectionType attribute and annoyingly underlines it even though it works when you ignore'n'run it, then use <f:attribute> instead.

<p:selectManyMenu ... >
    <f:attribute name="collectionType" value="java.util.LinkedHashSet" />
    ...
</p:selectManyMenu>

这篇关于com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel 处的 org.hibernate.LazyInitializationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆