我认为术语“存储库”通常被认为是在 Martin Fowler 的书Patterns of Enterprise Application Architecture 中描述的“repository pattern”。
存储库在域和数据映射层之间进行中介,
充当内存中的域对象集合。客户对象
以声明方式构造查询规范并将它们提交给
满意的存储库。可以添加和删除对象
存储库,因为它们可以来自简单的对象集合,以及
Repository 封装的映射代码将执行
在幕后进行适当的操作。
从表面上看,Entity Framework 完成了所有这些,并且可以用作存储库的简单形式。但是,存储库可能不仅仅是数据层抽象。
根据 Eric Evans 的《Domain Driven Design》一书,存储库具有以下优点:
- 他们为客户提供了一个简单的模型,用于获取持久性对象并管理其生命周期
- 它们将应用程序和域设计与持久性技术、多种数据库策略甚至多个数据源解耦
- 他们交流有关对象访问的设计决策
- 它们允许轻松替换虚拟实现以进行单元测试(通常使用内存中的集合)。
第一点大致相当于上面那一段,不难看出Entity Framework本身很容易做到。
有些人会认为 EF 也完成了第二点。但通常 EF 仅用于将每个数据库表转换为 EF 实体,并将其传递给 UI。它可能抽象了数据访问的机制,但几乎没有抽象出幕后的关系数据结构。
在主要面向数据的更简单的应用程序中,这似乎不是重点。但是随着应用程序的域规则/业务逻辑变得更加复杂,您可能希望更加面向对象。数据的关系结构包含对业务领域不重要但属于数据存储的副作用的特性并不罕见。在这种情况下,仅仅抽象持久性机制是不够的,还要抽象数据结构本身的性质。单独的 EF 通常无法帮助您做到这一点,但存储库层可以。
至于第三个优势,EF 不会(从 DDD 的角度)提供帮助。通常 DDD 不仅使用存储库来抽象数据持久性的机制,而且还提供有关如何访问某些数据的约束:
我们也不需要对更多的持久对象进行查询访问
方便遍历查找。例如,一个人的地址
可以从 Person 对象请求。最重要的是,任何
禁止访问 AGGREGATE 内部的对象,除非通过
从根遍历。
换句话说,你不会因为你的数据库中有一个地址表而有一个'AddressRepository'。如果您的设计选择以这种方式管理 Address 对象的访问方式,那么您将在 PersonRepository 中定义和实施设计选择。
此外,DDD 存储库通常是封装与域数据集相关的某些业务概念的地方。 OrderRepository 可能有一个名为OutstandingOrdersForAccount 的方法,它返回一个特定的Orders 子集。或者,客户存储库可能包含 PreferredCustomerByPostalCode 方法。
如果没有添加存储库抽象层,Entity Framework 的 DataContext 类将无法很好地支持此类功能。它们适用于 DDD 所谓的规范,它可以是简单的布尔表达式,发送到一个简单的方法,该方法将根据表达式评估数据并返回匹配项。
至于第四个优势,虽然我确信有某些策略可以让一个替代数据上下文,但将其包装在存储库中使其变得非常简单。
关于“工作单元”,这是 DDD 书中所说的:
将事务控制权留给客户端。 虽然 REPOSITORY 会在数据库中插入和删除,但通常不会
承诺任何事情。保存后提交是很有诱惑力的,例如,
但客户可能具有正确启动和
提交工作单元。事务管理会更简单,如果
REPOSITORY 不插手。