C# – Repository Pattern without an ORM

cdomain-driven-designormrepository-pattern

I am using repository pattern in a .NET C# application that does not use an ORM. However the issue I am having is how to fill One-to-many List properties of an entity. e.g. if a customer has a list of orders i.e. if the Customer class has a List property called Orders and my repository has a method called GetCustomerById, then?

  • Should I load the Orders list within the GetCustomerById method?
  • What if the Order itself has another list property and so on?
  • What if I want to do lazy loading? Where would I put the code to load the Orders property in customer? Inside the Orders property get{} accessor? But then I would have to inject repository into the domain entity? which I don't think is the right solution.

This also raises questions for Features like Change Tracking, Deleting etc? So i think the end result is can I do DDD without ORM ?

But right now I am only interested in lazy loading List properties in my domain entities? Any idea?

Nabeel

I am assuming this is a very common issue for anyone not using an ORM in a Domain Driven Design? Any idea?

Best Answer

can I do DDD without ORM ?

Yes, but an ORM simplifies things.

To be honest I think your problem isn't to do with whether you need an ORM or not - it's that you are thinking too much about the data rather than behaviour which is the key for success with DDD. In terms of the data model, most entities will have associations to most another entities in some form, and from this perspective you could traverse all around the model. This is what it looks like with your customer and orders and perhaps why you think you need lazy loading. But you need to use aggregates to break these relationships up into behavioural groups.

For example why have you modelled the customer aggregate to have a list of order? If the answer is "because a customer can have orders" then I'm not sure you're in the mindset of DDD.

What behaviour is there that requires the customer to have a list of orders? When you give more thought to the behaviour of your domain (i.e. what data is required at what point) you can model your aggregates based around use cases and things become much clearer and much easier as you are only change tracking for a small set of objects in the aggregate boundary.

I suspect that Customer should be a separate aggregate without a list of orders, and Order should be an aggregate with a list of order lines. If you need to perform operations on each order for a customer then use orderRepository.GetOrdersForCustomer(customerID); make your changes then use orderRespository.Save(order);

Regarding change tracking without an ORM there are various ways you can do this, for example the order aggregate could raise events that the order repository is listening to for deleted order lines. These could then be deleted when the unit of work completed. Or a slightly less elegant way is to maintain deleted lists, i.e. order.DeletedOrderLines which your repository can obviously read.

To Summarise:

  • I think you need to think more about behaviour than data
  • ORM's make life easier for change tracking, but you can do it without one and you can definitely do DDD without one.

EDIT in response to comment:

I don't think I'd implement lazy loading for order lines. What operations are you likely to perform on the order without needing the order lines? Not many I suspect.

However, I'm not one to be confined to the 'rules' of DDD when it doesn't seem to make sense, so... If in the unlikely scenario that there are a number of operations performed on the order object that didn't require the order lines to be populated AND there are often a large number of order lines associated to an order (both would have to be true for me to consider it an issue) then I'd do this:

Have this private field in the order object:

private Func<Guid, IList<OrderLine>> _lazilyGetOrderLines;

Which would be passed by the order repository to the order on creation:

Order order = new Order(this.GetOrderLines);

Where this is a private method on the OrderRepository:

private IList<OrderLine> GetOrderLines(Guid orderId)
{
    //DAL Code here

}

Then in the order lines property could look like:

public IEnumberable<OrderLine> OrderLines
{ 
    get 
    {
         if (_orderLines == null)
            _orderLines = _lazilyGetOrderLines(this.OrderId);

         return _orderLines;
    }
}

Edit 2

I've found this blog post which has a similar solution to mine but slightly more elegant:

http://thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance