我遇到了JPA CascadeType.REFRESH属性的一个奇怪问题。 我有一个简单的父子关系,在父域对象(LineEquipmentFormat)中我添加了如下的级联属性
OneToMany(cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REMOVE}, mappedBy = "lineEquipmentFormat")
public List<LineEquipmentFormatDivision> getLineEquipmentFormatDivisions() {
return lineEquipmentFormatDivisions;
}
但是当我从DB获取父LineEquipmentFormat对象时,我没有得到LineEquipmentFormatDivisions的列表。
我得到的错误是
17:46:34,251 ERROR [LazyInitializationException] failed to lazily initialize a collection of role: LineEquipmentFormat.lineEquipmentFormatDivisions, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: LineEquipmentFormat.lineEquipmentFormatDivisions, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentBag.toString(PersistentBag.java:506)
我使用的是Jboos 5.1和Oracle 10G。
请提供有关此错误的可能根本原因的更多输入。
由于
答案 0 :(得分:2)
当您将级联类型定义为刷新时,这意味着在父LineEquipmentFormat上调用entityManager.refresh()时,它也将在子LineEquipmentFormatDivisions上调用。但是,您收到的错误表示您在会话关闭时尝试懒惰地初始化集合。如果在会话关闭后需要此集合,则需要通过设置fetchType来急切地获取它们。
答案 1 :(得分:1)
我添加了如下的级联属性(...)但是当我从DB获取父级LineEquipmentFormat对象时,我没有得到LineEquipmentFormatDivisions的列表。
级联操作与EAGER或LAZY加载几乎没有关系,在你的情况下,你得到的错误(臭名昭着的LazyInitializationException
)意味着你试图访问一个懒惰的关联但是会话已经被关闭(所以Hibernate无法加载它)。
要避免这个“问题”,请:
fetchType
属性加载关联(如果你在大多数情况下不需要关联,那就是IMO将“口红放在猪身上”)在执行查询时使用FETCH JOIN
来获取此特定用例,例如:
SELECT f
FROM LineEquipmentFormat f LEFT JOIN FETCH f.lineEquipmentFormatDivisions
WHERE f.id = 1
使用 Open EntityManager In View 模式(在MVC上下文中)在请求进入时打开实体管理器并保持打开直到请求处理完毕(Spring有一个实现此模式的Serlvet filter或Interceptor)。
答案 2 :(得分:0)
感谢您的评论。
以下是我们最终如何实施它。
在获取“LineEquipmentFormat”父对象时,我们添加了以下附加代码。
LineEquipmentFormat lef = entityManager.find(LineEquipmentFormat.class,sysId);
if(lef!= null&amp;&amp; lef.getLineEquipmentFormatDivisions()!= null){
。lef.getLineEquipmentFormatDivisions()大小();
}
返回lef;
现在我们可以从这个父对象中获取子列表。