Domain driven design DDD中的数据访问?

Domain driven design DDD中的数据访问?,domain-driven-design,data-access,Domain Driven Design,Data Access,在阅读了Evan和Nilsson的书之后,我仍然不确定如何在域驱动的项目中管理数据访问。CRUD方法应该是存储库的一部分,即OrderRepository.GetOrdersByCustomer(customer),还是应该是实体的一部分:customer.GetOrders()。后一种方法似乎更面向对象,但它将在多个对象之间分配单个实体类型的数据访问,即Customer.GetOrders()、Invoice.GetOrders()、ShipmentBatch.GetOrders()等。插入和

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

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

原因是,

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

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

    CRUD ish方法应该是存储库的一部分…ish。但我认为你应该问为什么你有一堆积垢的方法。他们到底是干什么的?它们到底是干什么用的?如果您实际调用应用程序使用的数据访问模式,我认为这会使存储库更加有用,并且在您的域发生某些类型的更改时,您不必进行散弹操作

    CustomerRepo.GetThoseWhoHaventPaidTheirBill()
    
    // or
    
    GetCustomer(new HaventPaidBillSpecification())
    
    // is better than
    
    foreach (var customer in GetCustomer()) {
        /* logic leaking all over the floor */
    }
    
    “Save”类型的方法也应该是存储库的一部分

    如果您有聚合根,这就避免了存储库爆炸或逻辑分散:您没有4个实体的数据访问模式,只有聚合根上实际使用的模式


    这是我的0.02美元。

    尼尔森应用DDD&p的恼人之处在于,他总是以“我不会在现实世界的应用程序中这样做,但是……”开头,然后他的例子如下。回到主题:我认为OrderRepository.GetOrdersByCustomer(customer)是一个不错的选择,但是在ALT.Net邮件列表()中也有关于DDD的讨论

    我已经用了您所说的两种方法,现在我更喜欢的方法是持久无知(或PONO——普通Ole“.Net对象)方法,您的域类只担心成为域类。他们不知道如何持久化,甚至不知道是否持久化。当然,您有时必须对此保持务实,并考虑到诸如Id之类的内容(但即使如此,我也只使用具有Id的layer super类型,这样我就可以有一个像默认值这样的活动点)

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

    需要注意的一件事是存储库可能遭受的方法膨胀。GetOrderbyCustomer。。获取所有订单。。GetOrders30天售出。。这个问题的一个很好的解决方案是查看查询对象模式。然后,您的存储库就可以接收一个查询对象来执行


    我还强烈建议你研究一下像NHibernate这样的东西。它包含了许多使存储库如此有用的概念(标识映射、缓存、查询对象…)

    DDD通常更喜欢存储库模式,而不是您在Customer.Save中提示的活动记录模式

    活动记录模型的一个缺点是,它几乎假定只有一个持久性模型,而不包括一些特别侵入性的代码(在大多数语言中)

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

    对于许多人来说,拥有一个专门用于测试的存储库听起来很愚蠢,但是如果您使用存储库模型,您可能会发现您并不真正需要一个用于特定应用程序的数据库;有时,一个简单的文件存储库就可以做到这一点。在您知道自己需要数据库之前,将自己与数据库结合可能会受到限制。即使需要数据库,对InMemoryRepository运行测试也要快得多


    如果你没有太多的领域逻辑,你可能不需要DDD。ActiveRecord非常适合解决很多问题,尤其是当您拥有大部分数据和少量逻辑时。

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

    customer.Orders;
    
    因此,为了回答您的问题,在聚合根存储库上存在CRUD操作

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