存储库模式与DAL


Answers:


88

您绝对不是混淆事物的人。:-)

我认为问题的答案取决于您希望成为一名纯粹主义者。

如果您想要严格的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();
}

这是DAL还是存储库?在这种情况下,我猜两者都有。


5
在这里晚了聚会,但是为什么要用T []而不是List <T>(或类似的东西)呢?
Mike Kingscott 2010年

27
也许IEnumerable <T>是最好的。
Venemo

9
或IQueryable <T>
kenwarner

1
我认为IQueryable <T>是最佳选择,因为它允许您链接方法并推迟执行,让数据库完成所有工作。
0lukasz0 2012年

4
@kenwarner我认为返回IQueryable <T>会泄漏抽象。您应该从存储库返回域对象。
马修·马修(

42

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

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


23

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


26
首先要了解的是,作为模式的存储库是称为域驱动设计的较大系统的一部分。在DDD中,域对象被分组为聚合,每个聚合都有根。例如,PurchaseOrder是一个聚合根,而OrderItems是该聚合根内的子级。存储库仅处理聚合根。也就是说,例如,OrderItem永远不会独立于其聚集根而加载。因此,您将永远不会在DDD中拥有一个OrderItem存储库。但是,在非DDD系统中,可以使用OrderItemDao,因为Dao不限于聚合根。
令人沉思

NG,谢谢!我已经开始以这种方式看到它,但这很清楚。我必须开始阅读所有DDD文献!
大卫2010年

@bingle,有关聚合根以及存储库如何加载子对象的详细说明。多层应用程序中哪里有存储库?我可以看到它位于数据访问层库中,但是由于它加载了子对象,因此它应该存在于逻辑层库中吗?我的直觉告诉我数据访问层,但我希望您对此事发表意见。
Jeff LaFay 2013年

12

我一直在寻找类似问题的答案,并同意排名最高的两个答案。试图为自己澄清这一点,我发现,如果将规范与存储库模式紧密结合的规范实现为域模型的一流成员,那么我可以

  • 重复使用具有不同参数的规范定义,
  • 操作现有规范实例的参数(例如进行专门化),
  • 结合起来,
  • 在不需要执行任何数据库访问的情况下,对其执行业务逻辑
  • 当然,也可以独立于实际的存储库实现对它们进行单元测试

我什至可以说,除非将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

参见福勒的规范论文详细信息,(这就是我上面所基于的内容)。

DAL将具有专门的方法,例如

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

您可以看到这很快变得很麻烦,特别是因为您必须使用这种方法定义每个DAL / DAO接口,并且实现DAL查询方法。

在.NET中,LINQ查询可以是实现规范的一种方法,但是结合使用规范(表达式)可能不像使用本地解决方案那样平滑。有关此问题的一些想法在本SO问题中进行了描述。


2

我个人认为这全都与映射有关,请参阅:http : //www.martinfowler.com/eaaCatalog/repository.html。因此,存储库的输出/输入是域对象,在DAL上可以是任何对象。对我来说,这是一个重要的添加/限制,因为您可以为数据库/服务/使用不同布局的任何内容添加存储库实现,并且您有明确的位置可以专注于进行映射。如果您不使用该限制并在其他位置使用映射,那么采用不同的方式表示数据可能会影响不应更改的代码。


1

这全都与解释和上下文有关。它们可以非常相似,或者甚至可以非常不同,但是只要解决方案能够完成任务,名称就是什么!


1

存储库是一种模式,这是一种以标准化方式实现事物的方式,可以尽可能地重用代码。


1

使用存储库模式的优点是模拟数据访问层,以便您可以在不调用DAL代码的情况下测试业务层代码。还有其他很大的优势,但这对我来说似乎至关重要。


1
您仍然可以模拟DAL,它本身不必是存储库。重要的一点是,无论使用哪种数据访问策略,都应实现一个接口。这将使您可以使用IoC容器以及整齐地测试您的业务代码,而无需数据存储。
cdaq

0

据我了解,它们基本上可以表示同一件事-但命名因上下文而异。

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

Dal / Dao是数据层术语;应用程序的较高层根据存储库来考虑。


0

因此,在大多数(简单)情况下,DAO是存储库的实现吗?

据我了解,似乎DAO精确地处理了数据库访问(CRUD-是否没有选择?!),而存储库允许您抽象整个数据访问,也许是多个DAO(可能是不同数据源)的基础。

我在正确的道路上吗?


实际上,我反过来说,从一个简单的角度来看,存储库是DAO的一种特殊实现方式,但是,是的,您的方向正确。(CRUD中的R =读取,因此您可以选择。)
Jeromy Irvine,

0

在外部世界(即客户端代码)中,存储库与DAL相同,除了:

(1)它的插入/更新/删除方法仅限于以数据容器对象作为参数。

(2)对于读取操作,它可以采用简单的规范,例如DAL(例如GetByPK)或高级规范。

在内部,它与数据映射器层(例如,实体框架上下文等)一起执行实际的CRUD操作。

存储库模式不代表什么:-

此外,我已经看到人们经常感到困惑,除了将Insert / Update / Delete方法提交到数据库的所有内存中更改之外,还有一种单独的Save方法作为存储库模式示例实现。我们肯定可以在存储库中使用Save方法,但这不是存储库负责隔离内存中的CUD(创建,更新,删除)和持久性方法(在数据库中执行实际的写/更改操作)的职责,而是工作单位模式的责任。

希望这可以帮助!


0

有人可能会争辩说“存储库”是一个特定的类,而“ DAL”则是由存储库,DTO,实用程序类以及任何其他所需内容组成的整个层。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.