DDD中的数据访问?

时间:2008-09-16 21:12:30

标签: domain-driven-design data-access

在阅读了Evan和Nilsson的书之后,我仍然不确定如何在域驱动的项目中管理数据访问。 CRUD方法应该是存储库的一部分,即OrderRepository.GetOrdersByCustomer(客户),还是它们应该是实体的一部分:Customer.GetOrders()。后一种方法似乎更多OO,但它将在多个对象中分配单个实体类型的数据访问,即Customer.GetOrders(),Invoice.GetOrders(),ShipmentBatch.GetOrders()等。那么插入和更新呢?

6 个答案:

答案 0 :(得分: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 */
}

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

如果你有聚合根,这可以防止你有一个Repository爆炸,或者逻辑遍布全局:你没有4 x实体数据访问模式,只是你在聚合根上实际使用的模式

那是我的$ .02。

答案 1 :(得分:5)

DDD通常更喜欢使用Customer.Save提示的活动记录模式上的存储库模式。

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

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

对很多人来说,拥有一个专门的存储库只是为了测试声音傻瓜,但是如果你使用存储库模型,你可能会发现你并不真正需要一个特定应用程序的数据库;有时一个简单的FileRepository会做到这一点。在您知道自己需要之前向自己婚礼到数据库是有潜在限制的。即使需要数据库,对InMemoryRepository运行测试也要快得多。

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

答案 2 :(得分:4)

让我们退一步。 Evans建议存储库返回聚合根而不仅仅是实体。因此,假设您的客户是包含订单的聚合根,那么当您从其存储库中获取客户时,订单就随之而来。您可以通过导航从客户到订单的关系来访问订单。

customer.Orders;

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

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

答案 3 :(得分:3)

我已经完成了你所讨论的两种方式,我现在首选的方法是持久的无知(或PONO - Plain Ole'.Net Object)方法,你的域类只担心是域类。他们不知道如何坚持或即使他们坚持下去。当然,你有时必须务实这一点,并允许诸如Id之类的东西(但即便如此我只是使用具有Id的图层超级类型,所以我可以有一个点,其中像默认值这样的东西活着)

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

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

我也强烈建议调查像NHibernate这样的东西。它包含许多使存储库如此有用的概念(Identity Map,Cache,Query objects ..)

答案 4 :(得分:2)

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

原因是,

  1. 可测试性提高
  2. 关注点分离和模块化设计
  3. 从长远来看,当您添加实体,例程
  4. 时,更易于维护

    我不是专家,只是我的意见。

答案 5 :(得分:1)

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

相关问题