我们说我有一个POJO班Meal
。该类使用ORM(例如JPA + Hibernate)进行映射,因此我可以将其保存在DB中。除此之外,这个类包含一个List<Dish> dishes
(Dish是另一个映射的POJO),由ORM延迟加载。
现在我有了一个业务层方法Meal getNextDueMeal()
。这由UI层调用,然后向用户显示膳食。当然,也应该展示构成这顿饭的菜肴。
但是我应该怎么处理呢?如果我试图天真地遍历getMeals()
返回的列表,我会得到LazyInitializationException
。我可以在UI层维护EntityManger
,例如使用Spring的@Transactional
注释。但是,从业务逻辑返回的对象将保持持久性,即如果我以某种方式修改Meal
- &#34; POJO&#34;在UI中,一旦我从@Transactional
- 方法返回,它将自动保存,这可能不是我想要的。
tl; dr:业务层是否应该将持久对象返回到UI-Layer?如果没有,我该如何处理延迟加载?
答案 0 :(得分:2)
当您使用远程界面时,将实体作为业务层返回值返回并不是一个好主意。您可以定义一些 DTO 或数据传输对象,并从获取的实体中填充它们,并将这些DTO作为返回值返回。
业务层是否应该将持久对象返回到UI-Layer? 如果没有,我该如何处理延迟加载?
关于延迟加载,您可以将业务层中的所有必需值填充到DTO对象中,因此,在您的UI层中加载了所有必需的属性,您将不会遇到这些{ {1}}例外。
引自PoEAA:
数据传输对象中的字段非常简单 原语,简单类,如
LazyInitializationException
和String
s,或其他数据 转移对象。数据传输对象之间的任何结构都应该 是一个简单的图形结构 - 通常是层次结构 - 而不是 您在实体中看到的更复杂的图形结构。
在您的情况下,您可能会有Date
和MealDto
,如下所示:
DishDto
您可以使用另一个负责从相应实体组装DTO的抽象。例如,您可以使用public class MealDto {
private String name;
private List<DishDto> dishes;
// getters and setters
}
:
MealAssembler
答案 1 :(得分:2)
这取决于您实现视图或UI层的方式。
请记住,JSP和JSF是Server Side
个视图。这意味着在呈现视图时,他们可以访问JVM中的所有内容。在这种情况下,我看不出为什么service layer
(或业务层)无法将从数据库检索到的实体传递给要呈现的视图。
使用AngularJs和jQuery等框架进行Client Side
视图渲染有很多人气。这意味着一旦object
传递给视图,它就不再是JVM的一部分,因此您必须构建一个对象,该对象不需要再进行对JVM的进一步调用。在这种情况下,通常将对象编组为JSON或XML表示并将其发送到客户端。
在这两种情况下,一旦实体被移交给控制器层,它就在事务之外,将不再能够进行JPA调用或JDBC调用。如果您尝试引用尚未初始化的属性,则可能会导致LazyInitializationExceptions
。服务器端和客户端视图之间的一个区别是,在server side
技术中,当未初始化的属性未被引用时,不会出现Lazy
问题。然而,当一个对象被编组为client side
技术时,编组将尝试编组所有字段,这可能导致lazy
异常,即使最终视图没有使用这些字段。在这种情况下,您希望创建一个只有所需字段的DTO
或数据传输对象,编组人员可以在没有任何例外的情况下编组。
处理LazyInitializationExceptions
视图所需字段的方法是确保在视图尝试访问它们之前初始化它们。这通常需要多个查询或连接,这是一个有点不同的问题。