我一直想知道应该如何处理这种异常现象:
但是你怎么避免JPA LazyInitialization异常呢? DTO转换可能需要Lazy Fetched数据,但由于服务层处理了事务,因此无法进行转换。
我可以想到一些方法,但所有这些方法都很难看。将DTO转换放在服务层中对我来说似乎是最好的。
答案 0 :(得分:5)
是的,绝对最好在服务层中操纵DTO。在更新包含在DTO中的更改的实体时尤其如此,否则您将需要获取和更新分离的实体,将它们传递给服务,再将它们合并到持久性上下文等等。
" DTO应该在控制器中转换,服务层不需要知道它们。"
而不是这个,我会说更好的经验法则是控制器不需要了解实体。但是你可以使用分离的实体代替DTO来处理简单的情况,以避免创建大量的小型DTO类,尽管我个人总是使用DTO来保持一致并使以后的更改更容易。
答案 1 :(得分:2)
引发'LazyInitializationException'只是信号表明某些部分数据未加载,因此最佳解决方案是从控制器方法到服务级别进行多次调用,并获取DTO的所有必需字段。
不太优雅的选择是:
可以通过'org.hibernate.Hibernate.isInitialized'方法检测未加载的字段,并在DTO构建期间跳过它们,请参见此处完整示例: How to test whether lazy loaded JPA collection is initialized?
您可以将控制器方法标记为事务性,在调用服务级别后将打开hibernate会话,因此延迟加载将起作用。
答案 2 :(得分:1)
DTO是您应该在服务之上的层中使用的模型。只有服务应该知道实体模型。在简单的简并情况下,DTO模型可能看起来几乎像实体模型,这就是为什么许多人只会使用实体模型的原因。在人们获得真正的需求(迫使他们改变其使用数据的方式)之前,这种方法行之有效。这是DTO = Entity的幻想破灭的时候。
DTO通常是实体模型的子集或变形。关于LazyInitializationException
的观点是幻觉何时开始崩溃的完美例子。
服务应返回完全初始化的DTO,即不只是某些委托给实体对象的对象。从服务返回DTO后,不应出现任何延迟加载。这意味着您必须精确获取DTO所需的状态,并将该数据连接到要返回的对象中。由于这通常需要相当多的样板代码,并且有时会导致必须重复逻辑,因此人们倾向于通过在此处和此处散布一些访存联接来使LazyInitializationException
消失,从而更加坚持DTO = Entity幻象。
这就是为什么我启动了Blaze-Persistence Entity Views项目的原因,该项目将使您两全其美。易于使用,减少了样板,具有良好的性能和安全的模型,避免了意外错误。也许您想尝试一下,看看它能为您做什么?