业务层是否应该将持久对象返回到UI层?

时间:2016-03-20 17:47:32

标签: java spring jpa orm separation-of-concerns

我们说我有一个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?如果没有,我该如何处理延迟加载?

2 个答案:

答案 0 :(得分:2)

当您使用远程界面时,将实体作为业务层返回值返回并不是一个好主意。您可以定义一些 DTO 数据传输对象,并从获取的实体中填充它们,并将这些DTO作为返回值返回。

  

业务层是否应该将持久对象返回到UI-Layer?   如果没有,我该如何处理延迟加载?

关于延迟加载,您可以将业务层中的所有必需值填充到DTO对象中,因此,在您的UI层中加载了所有必需的属性,您将不会遇到这些{ {1}}例外。

它是如何工作的?

引自PoEAA

  

数据传输对象中的字段非常简单   原语,简单类,如LazyInitializationExceptionString s,或其他数据   转移对象。数据传输对象之间的任何结构都应该   是一个简单的图形结构 - 通常是层次结构 - 而不是   您在实体中看到的更复杂的图形结构。

在您的情况下,您可能会有DateMealDto,如下所示:

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视图所需字段的方法是确保在视图尝试访问它们之前初始化它们。这通常需要多个查询或连接,这是一个有点不同的问题。