Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement own lazy loading when objects in own DLL

If this has been answered already I apologise, but I could not find any answer to this.

In an interview question I had recently I was asked how I would implement Lazy Loading. The scenario is as follows:

solution:

  • website project
    • default.aspx
  • object collection project
    • Order
    • LineItem
  • Service Layer
    • OrderService
  • Repository Layer
    • OrderRepository

The Order object would have an IList. The order repository would have a method to return all orders (to be quicker it would not return all the lineitems for every Order so it would be null).

The question was "how would I do lazy loading for the Order object. I.e. There is an Order Object and the website calls myOrder.LineItems.

My first thought was the Order object would call the Order Service to get the lineitems, but this is not good design as the Objects would need to know about the service, and the service would need to know about the objects. Naturally the website could call the order service passing it the order / order ID to get the lineitems, but how could we make that bit invisible? So the Order object holds all its data, but some is only loaded as and when / if required?

Thanks and hope that all made sense.

Jon

like image 291
Jon Avatar asked Dec 22 '22 18:12

Jon


2 Answers

There would be three things I, as an interviewer, would look for in the answer.

  • Knowledge of how ORM frameworks handle lazy loading
  • Acknowledgement that you wouldn't implement this in production without considering an existing framework.
  • The actual design of a "home-grown" solution.

This is how I would answer this question.

Lazy loading a common piece of functionality implemented by ORM frameworks like NHibernate or Entity Framework. My first attempt would be use one of these frameworks(point 1)

If an ORM framework is out of the question I would implement lazy loading using an interception framework like Castle Interception or Unity Interception.(point 2).

To implement lazy loading from scratch I would use a Decorator pattern (bonus point), subclass the Order class and define lazy loading behaviour there. Here is design showing relevant properties:

class Order {
 public int ID {get;set;}
 public virtual IList<OrderLine> Lines{get;set;} 
}

interface IOrderRepository {
  Order GetOrder(id);
  IList<OrderLine> GetOrderLines(Order order);
}

class OrderService {

 IOrderRepository _repository;

 public OrderService(IOrderRepository repository) {
  _repository = repository;
 }

 public Order GetOrder(int id) {
   return new OrderDecorator(_repository.GetOrder(id));
 }
}

public class OrderDecorator : Order {
  public OrderDecorator (IOrderRepository repository) {
    _OrderLines = new Lazy<IList<OrderLine>>(()=>repository.GetOrderLines(this));
  }

  Lazy<IList<OrderLine>> _OrderLines;

  public override IList<OrderLine> Lines {
    get {
      if (base.OrderLines == null) 
        base.OrderLines = _OrderLines.Value;
      return base.OrderLines; 
    } 
    set {base.OrderLines=value;}
  } 
}

And here is the version without the Lazy<> fanciness. After editing to make sure the code strictly conforms to the decorator pattern, the lazy version doesn't actually add anything, so I'd just go with the below version.

public class OrderDecorator : Order {
  public OrderDecorator (IOrderRepository repository) {
    _Repo = repository;
  }
  IOrderRepository _Repo;

  public override IList<OrderLine> Lines {
   get {
     if (base.OrderLines == null)
       base.OrderLines = repository.GetOrderLines(this);

     return base.OrderLines; 
   } 
   set {base.OrderLines=value;}
 }
}

UPDATE Here is the project layout. There was a comment about coupling the Order and the repository. It actually isn't the case as the repository is coupled to the decorator, not not the order.

  • object collection project
    • Order
    • LineItem
  • Service Layer
    • OrderService
  • Repository Layer
    • OrderRepository
    • OrderDecorator
like image 186
Igor Zevaka Avatar answered Jan 31 '23 09:01

Igor Zevaka


You can store a lazy reference to the list using, for example, the Lazy class.

One of the constructors of that class receives a Func<T> which is a function used to instantiate/retrieve the actual value when requested.

A possible solution would be to inject that function into the Order object, initialized with something like:

var getlines = () => orderService.GetLineItems(orderId);

After that, it's just wrapping the Lazy<ICollection<LineItem>> with a property.

like image 35
Diego Mijelshon Avatar answered Jan 31 '23 11:01

Diego Mijelshon