【问题标题】:Correct usage of Entity AND DTO to provide Json in Restful web service正确使用实体和 DTO 在 Restful Web 服务中提供 Json
【发布时间】:2015-07-19 20:52:15
【问题描述】:

有很多文章指出 JPA/hibernate 不需要使用 DTO

使用视图模式中的打开会话或规范的组装阶段来避免未获取数据的问题。Hibernate 将开发人员从编写乏味的数据传输对象 (DTO) 中解放出来... 以上几行来自https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/best-practices.html

另外,在 SO 成员 Bohzo 的 article 中,我读到 DTO 很少需要

即使在 articles 反对暴露实体的声明中,当实体没有任何行为(当它们是 POJO 时)时,也不需要像在贫血领域模型中那样拥有 DTO

假设有一个实体类

class Department{
    List<Employee> employees //lazily loaded collection 

集合中的每个对象都包含另一个延迟加载的集合

 class Employee{
    List<Account> accounts

有一个 getDepartment() 方法 被一个restful服务用来提供部门的Json信息。

可能的解决方案是

解决方案 1) 根据休眠文档打开和关闭每个请求的休眠会话(控制器中最上面的方法是事务性的吗?)或者更好地使用 Spring 的 OpenSessionInViewFilter 按照这个 SO post

为什么休眠不能重新打开会话并获取延迟加载的对象而不是抛出异常?有没有办法使用 JPA/休眠进行配置?

解决方案 2) 与 hibernate doc 一样,另一种方法是进行 组装阶段。这到底是什么意思? 将 getDepartment API 分解为 DAO 的不同 API?

解决方案3)使用DTO 即使使用了DTO,持久层如何知道视图是否需要一个完全加载的部门。这个 导致将 API 分解为 getDepartmentOnly() getDepartmentWithEmployees() 和其他人说是获取部门对象的 100% 还是其中的一部分 一个 API 分解为多个实体,映射到多个 DTO

解决方案 4) 在 bohzo 的文章中,分页视图避免延迟加载,并通过查询获取有限的结果

请更正解决方案 2 并解释 hibernate 文档中的意图?

【问题讨论】:

  • 见我的answer to this question。是的,EJB3 承诺不再需要 DTO。当我们在 8 年前开始使用 EJB3 时,我们相信这个“​​口头禅”。在创建了 300 多个实体后,我们意识到这根本行不通,我们需要 DTO。正如我所说,请参阅我对另一个问题的回答。
  • 谢谢,但我的问题不是 DTO 是否“总是”需要。这似乎是基于意见的。我的问题是关于它们的正确用法。
  • 在安静的 Web 服务中公开模型被认为是不好的做法。更重要的是,API 永远不应该根据视图的需要来设计。所以,如果你的 API 是安静的,你应该使用 DTO。否则,你只是在做 RPC。
  • 请理解我的问题不是更好的做法。如何实现文档中关于不使用 DTO 的说明以及如何为本示例构建 DTO
  • 使用 DTO 不会让服务变得安静。通过公开实体,发送的实体表示可能与实体本身相同也可能不同。如果 DTO 只是复制实体什么有什么意义吗?在这里您可以找到在 jax-rs 服务中使用的实体adam-bien.com/roller/abien/entry/javaee_7_retired_the_dto 这是来自 jpa2 jcp 和 jsrs 成员的博客。 “总是”并不总是正确的

标签: java spring hibernate jpa design-patterns


【解决方案1】:

Hibernate 文档中的组装阶段意味着:

public Department getDepartmentWithEmployees(Long departmentId) {
   Department result = em.find(Department.class, departmentId);
   Hibernate.initialize(result.getEmployees());
   return result;
}

或者:

public Department getDepartmentWithEmployees(Long departmentId) {
   String query = "select d from Department d join fetch d.employees where d.id = :departmentId";
   ...
}

或者...

基本上,获取必要的数据以在代码可读性、可维护性与性能(不同 API 的数量与获取的数据量)之间取得平衡,这取决于您。

这不是 JPA/Hibernate 特定的问题;您还需要使用任何其他持久性框架(或直接 JDBC)来考虑这一点。

【讨论】:

  • 在 JPA 中是否有任何非休眠特定方法来获取延迟加载的实体?还遇到了stackoverflow.com/questions/16833893/…,它消除了 json 转换期间延迟加载的异常,或者我想在不需要获取它们的 api 中将延迟集合设置为 null 的另一种方式
  • 但这里也有两种方法,一种是初始化惰性集合,另一种是作为休眠杰克逊模块可以忽略的代理,或者我可以将其显式设置为空。所以使用DTO只是为了摆脱事务之外的延迟加载异常是不是很合理?
  • 是的,您可以在未初始化的代理上调用一个方法来触发其初始化。但我更喜欢Hibernate.initialize,因为它更明确,我不必关心代理是否真的完全初始化(例如,在 Hibernate 额外延迟集合上调用 .size() 只会初始化集合的大小,而不是它的元素) .
  • 我同意,使用 DTO 只是为了摆脱事务之外的延迟加载异常是不合理的。
猜你喜欢
  • 1970-01-01
  • 2017-03-28
  • 2012-11-15
  • 1970-01-01
  • 2016-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多