【发布时间】:2015-09-27 02:28:43
【问题描述】:
我很难理解存储库模式。
关于这个话题有很多意见,比如Repository pattern done right,还有其他的东西,比如Repository is the new Singleton,或者Don't use DAO use Repository,或者只是Spring JPA Data + Hibernate + MySQL + MAVEN,在某种程度上,存储库似乎与DAO相同对象。
我已经厌倦了阅读这些东西,因为恕我直言,这不是一件难事,因为它在很多文章中都有展示。
我是这样看的:看来我想要的是这样的:
------------------------------------------------------------------------
| Server |
------------------------------------------------------------------------
| | | |
Client <-|-> Service Layer <-|-> Repository Layer <-|-> ORM / Database Layer |
| | | |
------------------------------------------------------------------------
Service Layer 获取 *DTOobjects 并将它们传递给 Repository Layer,这基本上就是知道如何可以存储实体的“人”。
例如假设你有一些工具的组合(请注意这只是伪代码)
@Entity
class ToolSet {
@Id
public Long id;
@OneToOne
public Tool tool1;
@OneToOne
public Tool tool2;
}
@Entity
class Tool {
@Id
public Long id;
@OneToMany
public ToolDescription toolDescription;
}
@Entity
class ToolDescription {
@Id
public Long id;
@NotNull
@OneToOne
public Language language
public String name;
public String details;
}
我没有得到的是我从客户端获取ToolSetDTO 对象的部分。
据我目前的理解,我可以使用“知道如何存储”ToolSetDTO 的方法ToolSetRepository.save(ToolSetDTO toolSetDto) 编写ToolSetRepository。但是几乎每个教程都没有通过*DTO,而是通过Entity。
这里困扰我的是,如果你从上面拿我的ToolSet 示例,我必须执行以下步骤:
- 取
toolSetDto并检查是否不是null - 对于
toolSetDto拥有的每个tool*Dto
a) 如果具有有效的ID,则从DTO转换为Entity,否则创建一个新的数据库条目
b)toolDescriptionDto并转换/将其保存到数据库或创建一个新条目 - 在检查了上述情况后,实例化
ToolSet(实体)并将其设置为持久保存在数据库中
所有这些都太复杂了,不能简单地让服务功能(客户端接口)来处理。
我在想的是创建例如ToolSetRepository 但这里的问题是
- 是使用
ToolSet实体对象还是使用DTO对象? - 无论如何:
*Repository是否允许使用 其他存储库对象?就像我想保存ToolSet但我必须先存储Tool和ToolDescription- 我会在ToolSetRepository中使用ToolRepository和ToolDescriptionRepository吗?
如果是这样:为什么它不破坏存储库模式?如果此模式基本上是服务和我的 ORM 框架之间的一层,那么由于依赖原因,它只是不“感觉正确”向其他*Repository类添加依赖项。
我不知道为什么我无法理解这一点。这听起来并不复杂,但仍然有像Spring Data 这样的帮助。另一件事困扰着我,因为我真的不明白这如何让任何事情变得更容易。特别是因为我已经在使用 Hibernate - 我没有看到好处(但也许这是另一个问题)。
所以.. 我知道这是一个很长的问题,但我已经对它进行了几天的研究。我现在正在处理的现有代码开始变得一团糟,因为我无法看穿这种模式。
我希望有人能给我一个比大多数文章和教程更大的图景,这些文章和教程并没有超出实现一个非常非常简单的存储库模式示例。
【问题讨论】:
-
在我看来,ToolSetRepository 应该只知道 ToolSet 实体......并且在 ToolSet 上,您还可以拥有 JaxB 注释,以将实体用作 DTO。在客户端,您只有使用 jaxws clientgen 生成的 jaxb 类,这些类来自从 web 服务 url 接收的 wsdl 加上“?wsdl”......在服务器端,您会收到“非托管”实体。那么您必须使用 entitymanager.merge 将其置于托管状态。就这样。在我看来,只有在无法使用命名查询的复杂条件下才需要特定的存储库。例如标准 api 查询。
-
@StefanHeimberg 但是
ToolSetRepository将如何处理Tool和ToolDescription的持久性?那些应该已经被坚持了?如果此时应该已经坚持这些,那么我会在哪里做呢?在我的服务方法中这样做感觉不对,因为像ToolSet这样的复杂实体会使服务方法代码膨胀。恕我直言,服务方法应该只做一些初始化和基本检查,然后将工作委托给下一层。 -
如果您在服务层(事务边界)中收到“非托管”实体,然后在实体管理器上使用 merge(),则该实体已被实体管理器知道。服务方法完成后,事务提交,实体管理器中的更改被持久化到数据库中......
-
AFAIK Hibernate(和 JPA)是一个完整的 DAO 层,因为它的工作是连接到数据源(在本例中为数据库),尽管有底层细节(MySQL、Oracle、SQL Server 等)和您可以通过多种方式查询数据源。如果您想要/需要对您的实体使用特定查询,它允许您使用在 Repository 中指定使用的条件,因此最终 Hibernate 既是 Dao 又是 Repository。你将在它之上做的是创建你自己的层来抽象这个 dao(或存储库)或任何你用来实现它并继续编程的东西。
-
merge() 已经检查是否是新的。然后创建插入或更新查询。在我看来,这是底层 ORM 的责任。例如JPA。
标签: java spring hibernate repository-pattern