通过无知解决LazyInitializationException

maa*_*nus 16 java orm hibernate jpa hibernate-mapping

这里有无数的问题,如何解决"无法初始化代理"问题,通过急切提取,保持交易开放,打开另一个OpenEntityManagerInViewFilter,等等.

但是,是否可以简单地告诉Hibernate忽略该问题并假装该集合为空?在我的情况下,不提取它只是意味着我不在乎.

这实际上是以下Y的XY问题:

我正在上课

class Detail {
    @ManyToOne(optional=false) Master master;
    ...
}

class Master {
    @OneToMany(mappedBy="master") List<Detail> details;
    ...
}
Run Code Online (Sandbox Code Playgroud)

并且想要提供两种请求:一个返回一个master包含所有的请求details,另一个返回一个包含masters 的列表details.结果将由Gson转换为JSON.

我试过session.clearsession.evict(master),但他们不碰代替使用的代理服务器details.有用的是

 master.setDetails(nullOrSomeCollection)
Run Code Online (Sandbox Code Playgroud)

感觉相当hacky.我更喜欢"无知",因为它通常适用而不知道代理的哪些部分.

写一个Gson TypeAdapter忽略AbstractPersistentCollectionwith的实例initialized=false可能是一种方式,但这取决于org.hibernate.collection.internal,这肯定没有好处.捕获异常TypeAdapter并不会听起来好多了.

一些答案后更新

我的目标不是" 加载数据而不是异常",而是 "如何获取null而不是异常"

Dragan提出了一个有效的观点,即忘记获取和返回错误的数据会比异常更糟糕.但有一个简单的方法:

  • 仅为收集执行此操作
  • 从来没有用过null他们
  • 返回null而不是空集合作为未获取数据的指示

这样,结果永远不会被错误地解释.如果我忘记取一些东西,响应将包含null哪些无效.

Dra*_*vic 5

您可以利用Hibernate.isInitialized,它是Hibernate公共API的一部分。

因此,TypeAdapter您可以在中添加以下内容:

if ((value instanceof Collection) && !Hibernate.isInitialized(value)) {
   result = new ArrayList();
}
Run Code Online (Sandbox Code Playgroud)

但是,以我的谦虚意见,您通常不会采用这种方法。

“就我而言,不先获取它就意味着我不在乎。”

或这意味着您忘记了获取数据,现在返回错误的数据(比得到异常更糟糕;服务的使用者认为该集合为空,但不是)。

我不想提出“更好”的解决方案(这不是问题的主题,每种方法都有其自身的优势),但是我在大多数用例中解决此类问题的方式(这是通常采用的方法之一) )正在使用DTO:只需定义一个表示服务响应的DTO,将其填充在事务上下文中(不LazyInitializationException存在),然后将其提供给将其转换为服务响应的框架(json,xml等)。