7

我是域模型、POCO 和 DDD 的新手,所以我仍在努力思考一些想法。

我还没有弄清楚的一件事是如何保持我的域模型简单且与存储无关,但仍然能够以丰富的方式对其数据执行一些查询。

例如,假设我有一个包含 OrdemItems 集合的实体 Order。无论出于何种原因,我都想获得最便宜的订单商品,或者可能是目前没有库存的订单商品清单。我不想做的是从存储中检索所有订单项目并稍后过滤(太昂贵),所以我想最终以某种方式获得“SELECT .. WHERE ITEM.INSTOCK = FALSE”类型的数据库查询。我不想在我的实体中使用该 SQL 查询,或者任何变体是否会将我绑定到特定平台,例如 Linq2SQL 上的 NHibernate 查询。在这种情况下,常见的解决方案是什么?

4

5 回答 5

3

实体是域的“单元”。存储库和服务引用它们,反之亦然。这样想:你把车管所放在口袋里吗?

OrderItem不是聚合根;它不应该通过存储库访问。它的身份对于 a 来说是本地的Order,这意味着在谈论sOrder时,an 总是在范围内。OrderItem

为查询找到家的困难使我想到了服务。在这种情况下,它们将代表关于an本身Order很难Order知道的东西。

在域项目中声明意图:

public interface ICheapestItemService
{
    OrderItem GetCheapestItem(Order order);
}

public interface IInventoryService
{
    IEnumerable<OrderItem> GetOutOfStockItems(Order order);
}

在数据项目中声明实现:

public class CheapestItemService : ICheapestItemService
{
    private IQueryable<OrderItem> _orderItems;

    public CheapestItemService(IQueryable<OrderItem> orderItems)
    {
        _orderItems = orderItems;
    }

    public OrderItem GetCheapestItem(Order order)
    {
        var itemsByPrice =
            from item in _orderItems
            where item.Order == order
            orderby item.Price
            select item;

        return itemsByPrice.FirstOrDefault();
    }
}

public class InventoryService : IInventoryService
{
    private IQueryable<OrderItem> _orderItems;

    public InventoryService(IQueryable<OrderItem> orderItems)
    {
        _orderItems = orderItems;
    }

    public IEnumerable<OrderItem> GetOutOfStockItems(Order order)
    {
        return _orderItems.Where(item => item.Order == order && !item.InStock);
    }
}

此示例适用于任何 LINQ 提供程序。或者,数据项目可以使用 NHibernate 的ISessionICriteria做脏活。

于 2009-02-11T01:37:27.383 回答
3

域对象应该独立于存储,您应该使用存储库模式或 DAO 来持久化对象。这样你就强制分离关注点,对象本身不应该知道它是如何存储的。

理想情况下,将查询构造放在存储库中是个好主意,尽管我会在其中使用 ORM。

这是 Martin Fowler 对存储库模式的定义。

于 2009-02-06T19:04:13.510 回答
2

据我了解这种设计风格,您可以将查询封装在 OrderItemRepository(或者更合适的 OrderRepository)对象的方法中,该对象的职责是在一侧与 DB 通信,并在另一侧返回 OrderItem 对象。存储库对 OrderItem 实例的消费者隐藏数据库的详细信息。

于 2009-02-06T18:58:50.853 回答
0

我认为谈论“仅包含没有库存的 OrderItems 的订单”是没有意义的。“订单”(我想)代表客户订购的任何东西的完整列表;如果您正在过滤该列表,则您不再处理 Order 本身,您正在处理的是经过过滤的 OrderItems 列表。

我认为问题在于您是否真的想将 Orders 视为Aggregate Root,或者您是否也希望能够从数据访问层中提取任意 OrderItems 列表。

您说过在从数据库返回后过滤项目太昂贵了,但是除非您为每个订单平均数百或数千个 OrderItems(或者还有其他特别密集的处理大量 OrderItems 的事情),否则您可能试图过早地优化并使事情变得比他们需要的更困难。我认为,如果您可以将 Order 作为聚合根并在域逻辑中进行过滤,那么您的模型将更易于使用。

如果确实不是这种情况并且您需要在数据库中进行过滤,那么您可能需要考虑拥有一个单独的 OrderItem 存储库,该存储库将提供诸如“给我此订单的所有无库存的 OrderItems”之类的查询。然后,您会将它们作为IList<OrderItem>(或IEnumerable<OrderItem>)返回,因为它们不是完整的 Order,而是一些经过过滤的 OrderItems 集合。

于 2009-02-11T02:17:59.453 回答
-2

在服务层。

于 2009-02-11T01:51:07.100 回答