JPA 实体和 DTO 是否属于服务或 Spring 存储库层

Do JPA entities and DTOs belong to Service or Spring Repository layer

我想编写一个 JPA 应用程序,但我在理解存储库和服务概念时遇到问题:

假设我们有 3 个实体: A、B 和 C.

实体 A 在保存之前需要设置 B 和 C:A.setB(B)、A.setC(C)。

另外,为了阅读,我只想 return DTO,因为它们将使我摆脱 LazyInitializationException, Open Session In View Anti-Pattern, etc, and for modifying data I will use entities ( these guidelines are also described in this book High-Performance Java Persistence)。

首先,用户将使用一些将转换为 ABCGuiObject 的数据创建 HTTP POST。 REST 控制器将调用 serviceA.save(ABCGuiObject).

坚持选项:

选项 #1 - 该服务将创建 3 个对象 A、B、C 并将它们传递给 repositoryA.save(A,B,C)。 repositoryA 将在 a.setB 和 a.setC.

中执行

选项#2 - 该服务将创建 3 个对象 A、B、C,执行 a.setB 和 a.setC 并调用 repositoryA.save(A).

DTO检索

我想编写一个 JPQL 查询来获取一些 DTO。我不想将实体转换为 DTO,而是直接使用 JPQL 检索它们。

选项 #1 - repositoryA 将 return 直接作为 DTO。

选项 #2 - 服务会将 JPQL 查询传递给存储库 A,存储库 A 将具有通用查询方法 returns 一个 DTO。

您推荐哪些方法?

写入数据

服务层应该构造实体ABC的图并相应地连接它们(a.setBa.setC)并通过ABC 到存储库。如果你有一对多的关联,你可以 cascade entity state transitions.

读取数据

如果您想要 return DTO,最好直接从 JPA 和 Hibernate 获取 DTO。所以,你有两个选择:

这是一个主观的事情,但我会分享我的意见。 对于持久化选项,我推荐选项 #2。理想情况下,存储库应该只执行 "repository" 职责、服务,或者如果太复杂,您可以委托给工厂来构建 A 实体。

对于 DTO 检索,我会发出查询以检索实体(因此存储库将始终 return 实体),并将它们转换为 DTO。有人可能需要相同的存储库功能,他们可以选择转换为 DTO,而不是编写另一个带有 DTO 查询的 JPQL。

坚持选项 2。

DTO 对象通常加载惰性字段。如果您不为不同的用例编写单独的 query/mapping,这可能会损害性能。不要使用 DTO,而是根据用例初始化惰性字段以避免 LazyIntializationException。此外,它还可以为您节省大量从实体映射到实体的工作。

关于持久化,我会选择选项 2,但不适用于所有与服务相关的操作。如果您有简单的操作,例如addComment, enable/disable 那么最好只传递 id 并让服务处理实体本身。

对于 DTO,我建议您看一下 Blaze-Persistence 实体视图,看看 DTO 模式的实现有多容易。这是一个很好的 article 入门指南。