业务层是否应该return持久化对象到UI层?
Should the business layer return persistent objects to the UI layer?
假设我有一个 POJO class Meal
。此 class 映射到 ORM(例如 JPA + Hibernate),因此我可以将其保存在数据库中。除此之外,这个 class 包含一个由 ORM 延迟加载的 List<Dish> dishes
(Dish 是另一个映射的 POJO)。
现在我有一个业务层方法Meal getNextDueMeal()
。这由 UI 层调用,然后向用户显示膳食。当然,配餐的菜品也要展示出来。
但是我该如何处理呢?如果我尝试天真地遍历由 getMeals()
编辑的 return 列表,我会得到 LazyInitializationException
。我可以在 UI 层中维护一个 EntityManger
,例如通过使用 Spring 的 @Transactional
注释。但是然后从业务逻辑中编辑的对象 return 将保持持久性,即如果我以某种方式修改 UI 中的 Meal
-"POJO",一旦我修改它就会自动保存return 来自 @Transactional
方法,这可能不是我想要的。
tl;dr: 业务层 return 是否应该将对象持久化到 UI 层?如果没有,我该如何处理延迟加载?
当您使用远程接口时,将您的实体 return 作为您的 业务层 return 值并不是一个好主意。您可以定义一些 DTO 或 数据传输对象 并从获取的实体和 return 这些 DTO 中填充它们作为 return价值。
Should the business layer return persistent objects to the UI-Layer?
And if not, how do I deal with lazy loading?
关于Lazy Loading,您可以将业务层中的所有必需值填充到DTO对象中,因此,在您的UI层中,所有必需的属性都是已加载,您将不会遇到那些 LazyInitializationException
异常。
它是如何工作的?
引用自PoEAA:
The fields in a Data Transfer Object are fairly simple, being
primitives, simple classes like String
s and Date
s, or other Data
Transfer Objects. Any structure between data transfer objects should
be a simple graph structure—normally a hierarchy—as opposed to the
more complicated graph structures that you see in a Entity.
在你的情况下,你可能会有一个 MealDto
和一个 DishDto
,像这样:
public class MealDto {
private String name;
private List<DishDto> dishes;
// getters and setters
}
您可以使用另一个抽象负责从相应的实体组装 DTO。例如,您可以使用 MealAssembler
:
public class MealAssembler {
public MealDto toDto(Meal meal) {
MealDto dto = new MealDto();
dto.setName(meal.getName);
// populate the other stuff
return dto;
}
}
这在某种程度上取决于您如何实现视图或 UI 图层。
请记住 JSP 和 JSF 是 Server Side
视图。这意味着他们可以在呈现视图时访问 JVM 中的所有内容。在这种情况下,我看不出为什么 service layer
(或业务层)不能将从数据库检索到的实体传递给要呈现的视图。
Client Side
使用 AngularJs 和 jQuery 等框架进行视图渲染非常受欢迎。这意味着一旦将 object
传递给视图,它就不再是 JVM 的一部分,因此您必须构建一个不需要进一步调用 JVM 来呈现的对象。在这种情况下,通常将对象编组为 JSON 或 XML 表示并将其发送给客户端。
在这两种情况下,一旦实体被交给控制器层,它就在事务之外,将无法再进行 JPA 调用或 JDBC 调用。如果您尝试引用尚未初始化的属性,这可能会导致 LazyInitializationExceptions
。服务器端和客户端视图之间的一个区别是,在 server side
技术中,当未引用未初始化的属性时不会出现 Lazy
问题。但是,当对象针对 client side
技术进行编组时,编组器将尝试编组所有字段,这可能导致 lazy
异常,即使最终视图未使用这些字段。在这种情况下,您想要创建一个 DTO
或仅包含所需字段的数据传输对象,编组器将能够毫无例外地编组这些字段。
处理视图需要的字段 LazyInitializationExceptions
的方法是确保在视图尝试访问它们之前对它们进行初始化。这通常需要几个查询或一个连接,这是一个有点不同的问题。
假设我有一个 POJO class Meal
。此 class 映射到 ORM(例如 JPA + Hibernate),因此我可以将其保存在数据库中。除此之外,这个 class 包含一个由 ORM 延迟加载的 List<Dish> dishes
(Dish 是另一个映射的 POJO)。
现在我有一个业务层方法Meal getNextDueMeal()
。这由 UI 层调用,然后向用户显示膳食。当然,配餐的菜品也要展示出来。
但是我该如何处理呢?如果我尝试天真地遍历由 getMeals()
编辑的 return 列表,我会得到 LazyInitializationException
。我可以在 UI 层中维护一个 EntityManger
,例如通过使用 Spring 的 @Transactional
注释。但是然后从业务逻辑中编辑的对象 return 将保持持久性,即如果我以某种方式修改 UI 中的 Meal
-"POJO",一旦我修改它就会自动保存return 来自 @Transactional
方法,这可能不是我想要的。
tl;dr: 业务层 return 是否应该将对象持久化到 UI 层?如果没有,我该如何处理延迟加载?
当您使用远程接口时,将您的实体 return 作为您的 业务层 return 值并不是一个好主意。您可以定义一些 DTO 或 数据传输对象 并从获取的实体和 return 这些 DTO 中填充它们作为 return价值。
Should the business layer return persistent objects to the UI-Layer? And if not, how do I deal with lazy loading?
关于Lazy Loading,您可以将业务层中的所有必需值填充到DTO对象中,因此,在您的UI层中,所有必需的属性都是已加载,您将不会遇到那些 LazyInitializationException
异常。
它是如何工作的?
引用自PoEAA:
The fields in a Data Transfer Object are fairly simple, being primitives, simple classes like
String
s andDate
s, or other Data Transfer Objects. Any structure between data transfer objects should be a simple graph structure—normally a hierarchy—as opposed to the more complicated graph structures that you see in a Entity.
在你的情况下,你可能会有一个 MealDto
和一个 DishDto
,像这样:
public class MealDto {
private String name;
private List<DishDto> dishes;
// getters and setters
}
您可以使用另一个抽象负责从相应的实体组装 DTO。例如,您可以使用 MealAssembler
:
public class MealAssembler {
public MealDto toDto(Meal meal) {
MealDto dto = new MealDto();
dto.setName(meal.getName);
// populate the other stuff
return dto;
}
}
这在某种程度上取决于您如何实现视图或 UI 图层。
请记住 JSP 和 JSF 是 Server Side
视图。这意味着他们可以在呈现视图时访问 JVM 中的所有内容。在这种情况下,我看不出为什么 service layer
(或业务层)不能将从数据库检索到的实体传递给要呈现的视图。
Client Side
使用 AngularJs 和 jQuery 等框架进行视图渲染非常受欢迎。这意味着一旦将 object
传递给视图,它就不再是 JVM 的一部分,因此您必须构建一个不需要进一步调用 JVM 来呈现的对象。在这种情况下,通常将对象编组为 JSON 或 XML 表示并将其发送给客户端。
在这两种情况下,一旦实体被交给控制器层,它就在事务之外,将无法再进行 JPA 调用或 JDBC 调用。如果您尝试引用尚未初始化的属性,这可能会导致 LazyInitializationExceptions
。服务器端和客户端视图之间的一个区别是,在 server side
技术中,当未引用未初始化的属性时不会出现 Lazy
问题。但是,当对象针对 client side
技术进行编组时,编组器将尝试编组所有字段,这可能导致 lazy
异常,即使最终视图未使用这些字段。在这种情况下,您想要创建一个 DTO
或仅包含所需字段的数据传输对象,编组器将能够毫无例外地编组这些字段。
处理视图需要的字段 LazyInitializationExceptions
的方法是确保在视图尝试访问它们之前对它们进行初始化。这通常需要几个查询或一个连接,这是一个有点不同的问题。