What level is responsible for implementing the LazyLoading strategy for child objects of an object

Let's say you have order as the aggregate root. An order contains one or more line items.

As I understand it, it is the responsibility of the repository to create an instance of the order object when it is requested.

Line items can be loaded during the creation of an order object (loaded with high load) or a collection of item elements can be filled when a client code accesses it (lazy loaded).

If we use intensive loading, it seems that the repository code will take responsibility for moisturizing positions when creating an order.

However, if we use lazy loading, how is a repository created when accessing the LineItems collection without creating a dependency on the repository on the class of the order domain?

+1
source share
1 answer

The main problem is the ability Repositoryto get only aggregate roots (representing aggregates), so you cannot use Repositoryto get positions. This can lead to cumulative encapsulation failure.

I suggest something like:

//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
    ...
}

The most important thing here is that it IOrderItemListcorresponds to the domain layer, but OrderItemListProxycorresponds to the data level.

Finally,

  • Instead of IOrderItemListor another appropriate interface you can use IList<OrderItem>.
  • - .
  • db, , .
+2

All Articles