cod*_*pet 14 jsf jpa lazy-loading eager-loading selectmanymenu
尽管FetchType.EAGER
和JOIN FETCH
,我得到一个LazyInitalizationException
,同时增加一些对象,以一个@ManyToMany
通过收集JSF UISelectMany
组件,如我的情况<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>();
Run Code Online (Sandbox Code Playgroud)
的@Entity Company
,有FetchType.EAGER
:
@ManyToMany(mappedBy="employers", fetch=FetchType.EAGER)
private List<IdentUser> employee;
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
UISelectMany
在提交时导致异常的JSF 组件:
<p:selectManyMenu value="#{bean.user.employers}" converter="#{entityConverter}">
<f:selectItems value="#{bean.companies}" var="company" itemValue="#{company}" itemLabel="#{company.name}"/>
</p:selectManyMenu>
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪的相关部分:
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)
...
Run Code Online (Sandbox Code Playgroud)
这是怎么造成的,我该如何解决?
Bal*_*usC 29
提交时,JSF UISelectMany
组件需要创建一个全新的集合实例,并提交已提交和转换的值.它不会清除和重用现有的集合中的模型,可能要么得到体现在其他引用同一个集合,或可能会失败,UnsupportedOperationException
因为集合是不可修改的,如通过获得的那些Arrays#asList()
或Collections#unmodifiableList()
.
的MenuRenderer
,后面的渲染器UISelectMany
(和UISelectOne
)组件谁负责这一切,将默认创建基于集合的集合的一个全新的实例getClass().newInstance()
.LazyInitializationException
如果getClass()
返回Hibernate的实现,而Hibernate PersistentCollection
内部使用它来填充实体的集合属性,那么这将失败.该add()
方法即需要通过当前会话初始化底层代理,但没有,因为作业不是在事务服务方法中执行的.
要覆盖此默认行为MenuRenderer
,您需要通过组件的属性显式指定所需集合类型的FQN .对于一个属性,你想指定并为财产,你想指定(或如果顺序并不重要):collectionType
UISelectMany
List
java.util.ArrayList
Set
java.util.LinkedHashSet
java.util.HashSet
<p:selectManyMenu ... collectionType="java.util.LinkedHashSet">
Run Code Online (Sandbox Code Playgroud)
这同样适用于所有其他UISelectMany
组件,它们直接绑定到Hibernate管理的JPA实体.例如:
<p:selectManyCheckbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyCheckbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyListbox ... collectionType="java.util.LinkedHashSet">
<h:selectManyMenu ... collectionType="java.util.LinkedHashSet">
Run Code Online (Sandbox Code Playgroud)
另请参阅VDL文档等<h:selectManyMenu>
.遗憾的是,这并未在VDL文档中<p:selectManyMenu>
指定,但由于它们使用相同的渲染器进行转换,因此必须正常工作.如果IDE正在对一个未知collectionType
属性进行抽搐并且恼人地强调它,即使它在你忽略它运行它时也能正常工作,那么请改用它<f:attribute>
.
<p:selectManyMenu ... >
<f:attribute name="collectionType" value="java.util.LinkedHashSet" />
...
</p:selectManyMenu>
Run Code Online (Sandbox Code Playgroud)
解决方案:替换editUserBehavior.currentUser.employers
不受Hibernate管理的with集合.
为什么?当实体变得受管理时,Hibernate 会将HashSet
其替换为自己的实现Set
(是它PersistentSet
).通过分析JSF的实现MenuRenderer
,事实证明,它一度创造了新的Set
反思性.请参阅评论MenuRenderer.convertSelectManyValuesForModel()
//尝试反映无参数构造函数并在可用时调用
在PersistentSet
initialize()
调用构造期间- 由于此类仅用于从Hibernate调用 - 抛出了LazyInitializationException.
注意:这只是我的怀疑.我不知道你的JSF和Hibernate的版本,但更有可能的是这种情况.
归档时间: |
|
查看次数: |
2748 次 |
最近记录: |