哪个层负责为实体的子对象实现延迟加载策略

时间:2014-09-14 01:01:09

标签: domain-driven-design

假设您有一个订单作为聚合根。订单包含一个或多个订单项

据我了解,存储库负责在被询问时实例化订单对象。

可以在创建订单对象时加载订单项(急切加载),也可以在客户端代码(延迟加载)访问订单项集时填充这些订单项。

如果我们使用预先加载,似乎存储库代码将负责在创建订单时保护订单项。

但是,如果我们使用延迟加载,那么在访问LineItems集合时如何调用存储库而不从订单域类创建对存储库的依赖?

1 个答案:

答案 0 :(得分:2)

主要问题在于Repository能够获得仅聚合根(呈现聚合),因此您无法使用Repository来获取订单项。这可能导致聚合封装违规。

我提出的建议如下:

//Domain level:

public interface IOrderItemList {

   IEnumerable<OrderItem> GetItems();

}

public class Order {

    private IOrderItemList _orderItems;

    public IEnumerable<OrderItem> OrderItems 
          { get { return _orderItems.GetItems() } };

    public Order(IOrderItemList orderItems) 
    {
        _orderItems = orderItems;
    }
}

public class OrderItemList : IOrderItemList
{
    private IList<OrderItem> _orderItems;

    public IEnumerable<OrderItem> GetItems() {
        return _orderItems; //or another logic
    }

    //other implementation details
}

//Data level

public class OrderItemListProxy : IOrderItemList
{
    //link to 'real' object
    private OrderItemList _orderItemList;

    private int _orderId;
    //alternatively:
    //private OrderEntity _orderEntity;

    //ORM context
    private DbContext _context;

    public OrderItemListProxy(int orderId, DbContext context)
    {
       _orderId = orderId;
       _context = context;
    }

    public IEnumerable<OrderItem> GetItems() {
        if (_orderItemList == null) 
        {
            var orderItemEntities = DbContext.Orders
              .Single(order => order.Id == _orderId).OrderItems;

            var orderItems = orderItemEntites.Select(...);
            //alternatively: use factory to create OrderItem from OrderItemEntity
            _orderItemList = new OrderItemList(orderItems);
        }
        return _orderItemList.GetItems();
    }

}

public class OrderRepository
{
   //ORM context
   private DbContext _context;

    Order GetOrder(int id)
    {
        var orderEntity = _context.Single(order => order.Id == id);
        var order = new Order(new OrderItemListProxy(id, _context))
        //alternatively:
        //var order = new Order(new OrderItemListProxy(orderEntity, _context))
        ...
        //init other fields
        ...
    }
    //other methods
    ...
}

最重要的是,IOrderItemList对应于域层,但OrderItemListProxy对应于数据层。

最后,

  1. 您可以使用IList<OrderItem>代替自定义IOrderItemList或其他适当的界面。
  2. 代理实施可能会有所不同。
  3. 我没有提供使用数据库上下文的最佳实践,它可能取决于您使用的技术。