存储库模式与DAL

Mik*_*ike 92 asp.net-mvc data-access-layer

它们是一样的吗?刚看完Rob Connery的店面教程,他们似乎是类似的技术.我的意思是,当我实现一个DAL对象时,我有GetStuff,Add/Delete等方法,我总是首先编写接口,这样我以后就可以切换db了.

我混淆了什么吗?

Kim*_*jor 87

你绝对不是那些混淆事物的人.:-)

我认为这个问题的答案取决于你想要多少纯粹主义者.

如果你想要一个严格的DDD观点,那将会带你走一条路.如果您将存储库视为一种模式,该模式帮助我们标准化了分隔服务和数据库的层的接口,那么它将使您失去另一个.

从我的角度来看,存储库只是一个明确指定的数据访问层.换句话说,是实现数据访问层的标准化方法.不同的存储库实现之间存在一些差异,但概念是相同的.

有些人会在存储库中添加更多DDD约束,而其他人则会将存储库用作数据库和服务层之间的方便中介.像DAL这样的存储库将服务层与数据访问细节隔离开来.

一个似乎使它们与众不同的实现问题是,通常使用采用规范的方法创建存储库.存储库将返回满足该规范的数据.我见过的大多数传统DAL都有更多的方法,其中方法将采用任意数量的参数.虽然这可能听起来有点小差异,但当您进入Linq和Expressions领域时,这是一个很大的问题.我们的默认存储库界面如下所示:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}
Run Code Online (Sandbox Code Playgroud)

这是DAL还是存储库?在这种情况下,我猜它两者.

  • 也许IEnumerable <T>会是最好的. (26认同)
  • 或IQueryable <T> (8认同)
  • 迟到了这里,但为什么T [],而不是List <T>(或类似的)? (5认同)
  • @kenwarner我认为返回IQueryable <T>会泄漏抽象.您应该从存储库返回域对象. (4认同)

Jer*_*ine 41

存储库是一种可以以多种不同方式应用的模式,而数据访问层则负有非常明确的责任:DAL必须知道如何连接到数据存储以执行CRUD操作.

存储库可以是DAL,但它也可以位于DAL之前,并充当业务对象层和数据层之间的桥梁.使用哪种实施方式因项目而异.


pon*_*tic 23

一个很大的区别是DAO是处理域中任何实体的持久性的通用方法.另一方面,存储库仅处理聚合根.

  • 首先要理解的是,作为模式的存储库是更大系统的一部分,称为域驱动设计.在DDD域中,对象被分组为聚合,每个聚合都具有聚合根.例如,PurchaseOrder是聚合根,OrderItems是聚合根中的子项.存储库仅处理聚合根.也就是说,例如,OrderItem永远不会独立于它的aggreate root加载.因此,您永远不会在DDD中拥有OrderItem存储库.但是,在非DDD系统中,您可以拥有OrderItemDao,因为Dao不限于聚合根. (26认同)
  • 你能详细说明一下吗? (3认同)

Tho*_*ung 12

我正在寻找类似问题的答案,并同意两个排名最高的答案.试图为自己澄清这一点,我发现,如果与Repository模式一起使用的规范被实现为域模型的一流成员,那么我可以

  • 重用具有不同参数的规范定义,
  • 操纵现有规范实例的参数(例如专门化),
  • 结合他们,
  • 无需进行任何数据库访问即可对它们执行业务逻辑,
  • 当然,它们独立于实际的Repository实现进行单元测试.

我甚至可能走得这么远并说明除非 Repository模式与Specification模式一起使用,否则它不是真正的"Repository",而是DAL.伪代码中一个人为的例子:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅Fowler的规范论文(这就是我基于上述内容).

DAL会有专门的方法,如

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')
Run Code Online (Sandbox Code Playgroud)

您可以看到它如何快速变得繁琐,特别是因为您必须使用此方法定义每个DAL/DAO接口实现DAL查询方法.

在.NET中,LINQ查询可以是实现规范的一种方式,但组合规范(表达式)可能不如本土解决方案那样平滑.本SO问题中描述了一些有关这方面的想法.


rem*_*ade 0

据我了解,它们的含义基本上是相同的 - 但命名根据上下文而有所不同。

例如,您可能有一个实现 IRepository 接口的 Dal/Dao 类。

Dal/Dao是数据层术语;应用程序的较高层会根据存储库进行思考。