2008-09-16 74 views
10

在阅读Evan和Nilsson的书籍后,我仍然不确定如何管理域驱动项目中的数据访问。如果CRUD方法是存储库的一部分,即OrderRepository.GetOrdersByCustomer(customer),或者它们应该是实体的一部分:Customer.GetOrders()。后一种方法看起来更多OO,但它将为多个对象(即Customer.GetOrders(),Invoice.GetOrders(),ShipmentBatch.GetOrders()等)中的单个实体类型分配数据访问。怎么样插入和更新?DDD中的数据访问?

回答

15

CRUD-ish方法应该是Repository的一部分...... ish。但我想你应该问为什么你有一堆CRUD方法。他们真的是吗?他们是什么真的是?如果您实际调用应用程序使用的数据访问模式,我认为这会使存储库更加有用,并且在您的域发生某些类型的更改时,不必进行霰弹枪手术。

CustomerRepo.GetThoseWhoHaventPaidTheirBill() 

// or 

GetCustomer(new HaventPaidBillSpecification()) 

// is better than 

foreach (var customer in GetCustomer()) { 
    /* logic leaking all over the floor */ 
} 

“保存”类型的方法也应该是存储库的一部分。

如果您拥有聚合根,这可以防止存储库爆炸或逻辑分散:您没有4 x个实体数据访问模式,只是您实际在聚合中使用的实体根。

这是我的$ .02。

2

即使在DDD中,我也会将数据访问类和例程与实体分开。

的原因是,

  1. 可测性提高的担忧
  2. 分离和模块化设计
  3. 从长远来看更容易维护,当您添加的实体,例程

我不是专家, 只是我的观点。

1

Nilsson的应用DDD & P令人讨厌的事情是,他总是以“我不会在真实世界的应用程序中这样做,但......”然后他的例子如下。返回主题:我认为OrderRepository.GetOrdersByCustomer(customer)是要走的路,但也有关于DDD的ALT.Net邮件列表(http://tech.groups.yahoo.com/group/altdotnet/)的讨论。

3

我已经完成了你所说的两种方式,现在我的首选方法是持续的无知(或PONO - Plain Ole'.Net对象)方法,其中你的域类只担心是域类。他们不知道他们如何坚持或甚至是坚持不懈。当然,你必须时时务实,并且允许诸如Id之类的东西(但是即使如此,我也只是使用了具有Id的图层超类型,所以我可以拥有一个像默认值一样的单个点)

主要原因是我努力遵循单一责任原则。通过遵循这个原则,我发现我的代码更具可测试性和可维护性。在需要时进行更改也容易得多,因为我只有一件事需要考虑。

有一点需要注意的是存储库可能遭受的方法膨胀。 GetOrderbyCustomer.GetAllOrders.GetOrders30DaysOld ..等等。这个问题的一个很好的解决方案是查看查询对象模式。然后你的仓库可以接受一个查询对象来执行。

我也强烈建议寻找像NHibernate的东西。它包含许多使存储库如此有用的概念(标识映射,高速缓存,查询对象..)

5

DDD通常优先于您使用Customer.Save提示的活动记录模式的存储库模式。

Active Record模型的一个缺点是它几乎假设一个持久性模型,除了一些特别侵入性的代码(在大多数语言中)。

存储库接口在域图层中定义,但不知道数据是否存储在数据库中。使用存储库模式,我可以创建一个InMemoryRepository,以便我可以孤立地测试域逻辑,并在应用程序中使用依赖注入来让服务层实例化一个SqlRepository。

对很多人来说,拥有专门用于测试的特殊存储库听起来很愚蠢,但是如果使用存储库模型,您可能会发现您并不需要特定应用程序的数据库;有时候一个简单的FileRepository会起作用。在知道需要数据库之前将自己嫁接到数据库可能会受到限制。即使数据库是必需的,对InMemoryRepository运行测试也要快很多。

如果你没有太多的领域逻辑,你可能不需要DDD。 ActiveRecord非常适用于很多问题,特别是如果您主要有数据和一点逻辑。

4

让我们退后一秒。 Evans建议存储库返回聚合根,而不仅仅是实体。因此,假设您的客户是一个包含订单的聚合根,那么当您从其存储库中提取客户时,订单就会随之而来。您将通过浏览客户与订单之间的关系来访问订单。

customer.Orders; 

因此,要回答您的问题,CRUD操作存在于聚合根存储库中。

CustomerRepository.Add(customer); 
CustomerRepository.Get(customerID); 
CustomerRepository.Save(customer); 
CustomerRepository.Delete(customer);