业务层是不是应该将持久对象返回给 UI 层? [关闭]

Posted

技术标签:

【中文标题】业务层是不是应该将持久对象返回给 UI 层? [关闭]【英文标题】:Should the business layer return persistent objects to the UI layer? [closed]业务层是否应该将持久对象返回给 UI 层? [关闭] 【发布时间】:2016-03-20 17:47:31 【问题描述】:

假设我有一个 POJO 类 Meal。此类使用 ORM 映射(例如 JPA + Hibernate),因此我可以将其保存在数据库中。除其他外,此类包含由 ORM 延迟加载的 List<Dish> dishes(Dish 是另一个映射的 POJO)。

现在我有一个业务层方法Meal getNextDueMeal()。这由 UI 层调用,然后将餐点显示给用户。当然,组成餐点的菜品也应该展示出来。

但是我应该如何处理呢?如果我尝试天真地遍历getMeals() 返回的列表,我会得到LazyInitializationException。我可以在 UI 层中维护一个EntityManger,例如通过使用 Spring 的 @Transactional 注释。但是从业务逻辑返回的对象将保持持久性,即如果我以某种方式修改 UI 中的Meal-“POJO”,一旦我从@Transactional-方法返回,它就会自动保存,这可能不是我想要什么。

tl;dr: 业务层是否应该将持久对象返回给 UI 层?如果没有,我该如何处理延迟加载?

【问题讨论】:

【参考方案1】:

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

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

关于延迟加载,您可以将业务层中所有必需的值填充到 DTO 对象中,因此,在您的 UI 层中,所有必需的属性都已加载并且您不会遇到那些 @ 987654322@ 异常。

它是如何工作的?


引用PoEAA:

数据传输对象中的字段相当简单,即 原语,像Strings 和Dates 这样的简单类,或其他数据 转移对象。数据传输对象之间的任何结构都应该 是一个简单的图结构——通常是一个层次结构——而不是 您在实体中看到的更复杂的图形结构。

在您的情况下,您可能会有一个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;
    

【讨论】:

【参考方案2】:

这在某种程度上取决于您如何实现视图或 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 的方法是确保在视图尝试访问它们之前对其进行初始化。这通常需要几个查询或一个连接,这是一个有点不同的问题。

【讨论】:

以上是关于业务层是不是应该将持久对象返回给 UI 层? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis开发的配置

您是不是应该从业务层(或服务层、域模型等)返回 BindingList?

自定义框架

业务层 (BLL) 数据访问层 (DAL) 和 UI 之间的通用结构?

面向对象——三层架构(表现层业务层持久层)

从 DAL 返回数据对象