DDD and repositories. Without nHibernate but with lazy loading

Domain driven design has become a very prominent way to develop software. A central domain model is used by all participants. To the end user it is a representation of the real  world. To the coder the model is a class model, working with the real domain world boils down to instantiating objects from these classes. In meetings we find ourselves often discussing a Visual Studio class diagram. Nothing fancy, but it works quite well. The domain user recognizes her entities, their data and behavior, the developer recognizes his classes, properties and methods.

In DDD these domain objects interact with the database through repositories. The methods of a repository return (sets of) domain objects as read from the database or accept domain objects which will be persisted to the database. nHibernate is a wonderful tool to build these repositories. All you have to do is define a mapping between domain classes and databases tables and nHibernate will take care of the tedious sql stuff. As a bonus you get a nice API for querying.

But there are reasons not to use nHibernate.

  1. Learning curve. In some teams the jump from sql scattered between the tags of a web page, stored procedures and wherever else to an O/R mapper is to big. Getting all database access together in one assembly is a big step forward on itself.
  2. Database server specific functionality. In a current project we are using SQL 2008 because we need the specific geographical functionality. At the time we started the project SQL 2008 was not feature stable yet, the nHibernate support was not quite there  either and the specific geographical queries would require a lot of sql passthrough. Combined with point 1 it was obvious we were going to do the sql ourselves.
  3. Restricted permissions on the application hoster. To do its magic nHibernate uses a lot of reflection. Reflection requires more priviliges than the partial trust many a shared hoster does offer. I tried to get nHibernate to work under partial trust but did not succeed. Perhaps it is possible with nHibernate 2.0

But not using nHibernate does not mean you cannot work in DDD style. Using the repository pattern is still the way to go. In the remainder of this post I will briefly demonstrate that and will focus on lazy loading. This is a programming aspect of domain objects which makes life for you as a coder so much easier and your code such a lot clearer and easier to maintain. Given the domain model of last figure, it is clear to code like this

foreach (var orderLine in myOrder.Lines)

{

    myTotal += orderLine.Article.Price;

}

When you need to think about the database stuff behind this things get complicated. The order has to be read from an orders table. The orderdetails are read from another table and for every orderline a row has to be read from the articles table. The only way to get this working is by implementing lazy loading. That is read the data from the database when it is requested, not any earlier than that. With nHibernate you get lazy loading for free. We had to do it ourselves. The solution presented here works well for us. But don’t take it for granted, we have to jump through some hoops. Feel free to comment. Anything to simplify the matter will improve our code.

The domain layer itself should suffer from persitance ignorance. That is it should be completely unknown to the domain object itself how and where it it persisted. The concession I have to make is that the domain object cannot ignore the fact that it is persited in some way and that it does have a certain price to retrieve data. To express this I define delegates with the domain classes , that is the signature of methods which will actually retrieve a domain object.

Take the article class

public class Article

{

    public int Id { get; private set; }

    public string Name { get; private set; }

    public decimal Price { get; private set; }

}

 

public delegate Article OnRequestArticle(int id);

This delegate is used by the order line class to lazyload an article

public class OrderLine

{

    public OrderLine(int articleId, int numberOrdered)

    {

        this.articleId = articleId;

        NumberOrdered = numberOrdered;

    }

 

    public int NumberOrdered { get; set; }

    public static OnRequestArticle RequestArticle { get; set; }

    private int articleId;

    private Article article;

    public Article Article

    {

        get

        {

            if (article == null)

                if (RequestArticle != null)

                    article = RequestArticle(articleId);

            return article;

        }

    }

}

The article of the orderline is instantiated as a null object. The first time the article is requested the static delegate property is fired to actually retrieve the article. To do that I need the article id. Which is passed in the constructor but not exposed by the domain object. In case you need it it is requested as orderLine.Article.ID

Likewise the orderlines define a delegate, this one expresses that orderlines come in a set, all belonging to the same order.

public delegate List<OrderLine> OnRequestOrderLines(Order forOrder);

This delegate is used in the Order domain class

public static OnRequestOrderLines RequestOrderLines { get; set; }

private List<OrderLine> lines;

public List<OrderLine> Lines

{

    get

    {

        if (lines == null)

            if (RequestOrderLines != null)

                lines = RequestOrderLines(this);

        return lines;

    }

}

Using these static delegates we can have lazy loading. For the delegates to work they have to be wired up. Before doing that we have to take a look at implementing the repositories.

This demo project has three repositories: Orders, Articles and Customers. I will not dive into the details of the implementation, you can find those in a previous post. What is important for now are the signatures of the repository methods. This is the OrderRepository.

public class OrderRepository

{

    public Order GetOrder(int orderId)

    {}

 

    public List<Order> ListOrders()

    {}

 

    public List<OrderLine> GetOrderLines(Order forOrder)

    {}

}

The last method is quite interesting as it’s signature matches the OnRequestOrderLines delegate. It is the one which has to be wired to the Order’s  RequestOrderLines property.

The repository has a helper class Lazyloaders which exposes all lazy loading methods as static methods.

public class LazyLoaders

{

    public static List<OrderLine> RequestOderLines(Order order)

    {

        var orderRepository = new OrderRepository();

        return orderRepository.GetOrderLines(order);

    }

    public static Article RequestArticle(int articleId)

    {

        var articleRepository = new ArticleRepository();

        return articleRepository.GetArticle(articleId);

    }

}

A repository object has very real instance members such as the connection to the database. It is not desired to have such a connection as a static member of the repository class. So it’s not possible to declare these static lazyloader members as members of the repository. That’s the main reason for the helper class.

The lazyloaders have to be static as they are wired to a static property of the domain objects. This wiring up is done in the static constructor of the repository. A static constructor is fired only once, at the moment in your code the class is actually used the first time.

public class OrderRepository

{

    static OrderRepository()

    {

        Order.RequestOrderLines = LazyLoaders.RequestOrderLines;

        OrderLine.RequestArticle = LazyLoaders.RequestArticle;

    }

 

    public Order GetOrder(int orderId)

    {}

 

    public List<Order> ListOrders()

    {}

 

    public List<OrderLine> GetOrderLines(Order forOrder)

    {}

}

In the static constructor of the repository the domain class is given an implementation of the lazyloaders. And now I am there and do have lazy loading for my orders and orderlines.

It works. There are some things I don’t quite like

  • The domain objects have to expose public delegate properties. These are needed by the repositories but for anything else they can be confusing.
  • The orderrepository has to expose the GetOrderLines method. This method makes no sense to any code outside the repositories. There are no orderlines without an order. The only way to access orderlines should be through their order. The lazy loading will return the orderlines. Lazy loading does need this method. Nobody else does. Any suggestion to hide this method is appreciated.
  • I have to keep the article ID in the orderline. It is hidden and only required for the lazy loading. But I don’t like having an article Id and an Article in my orderline object.

But as a whole this solution is quite satisfying for us. You might wonder whether it performs well. When the  simple loop we started with executes a lot is happening behind the scenes.

foreach (var orderLine in myOrder.Lines)

{

    myTotal += orderLine.Article.Price;

}

For every iteration in the loop an article repository is created and a database query is performed.  When it comes to the actual performance the only thing which really counts is database access. Don’t worry about instantiating POCO’s, do worry about complex sql. That’ s where the real bottleneck is. In this case I’m firing a series of short and simple sql statements. The ado.net connection pooling will ensure the multiple subsequent connections to the DB will be fast. And in real life the code presented here works fast and smooth.

The real plus lies in the real part of the application, where the code does things all kind of things with the domain objects. And never, ever has to worry when or how the data is read into the domain object.

I still do miss nHibernate. Writing all the sql, and especially maintaining it, is tedious and can be pretty boring. Except for the geographical stuff. But to all other parts of the application it is transparent whether the repositories are hand work or implemented by an O-R mapper.

I do hope to have made clear that you main goal should be coding against a domain model, and not using an O-R mapper. And I do hope you have suggestions to make my life even easier.

This entry was posted in Coding, Data. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/pvanooijen/default.aspx pvanooijen

    In case I only wanted to know the total it would be indeed not very effficient.
    In case I ocassionally want to list all articles descriptions and the like, FI in an invoice, I still needed to load the articles.
    It all depends. To reverse your statement: Never let pragmatism override a good domain model.
    The real bad thing is that I have to decide in the domain model’s implementation about lazy / eager loading.

  • Gary Hall

    foreach (var orderLine in myOrder.Lines)
    {
    myTotal += orderLine.Article.Price;
    }

    That code would require far too many database hits to justify the cleanliness of the DO. When crossing process boundaries – especially distributed ones – your interface needs to be chunky and not chatty. The fine-grained control of DOs is totally anathema to this. Fowler’s PoEAA covers this nicely. In this instance, you’d want to have the SQL return your the total price of an order. Never let a desire for DDD purity override pragmatism.

  • http://petersgekko.codebetter.com pvanooijen

    I see no objections to using static code for this kind of things. My static code lays the plumbing when the repositories are loaded. The plumbing will not change after load. So I even like the name “static”. DI would work but what extra will it give me here ?

    Yes I do violate SRP. But at least the DO only carries the interface to loading and is completely unaware of its implementation. It is a trade-off.

    I can load eager, no problem. But have to make that decission in the DO.

    I don’t use a proxy because it requires reflection. In some projects I just cannot choose my server and the permissions there. I just need a reflectionless solution.

    Learning nh pays off, yes. But in some environments the problem NH is going to solve has to be clear first. FIrst step is to scrape all DB access code together and make clear how it should fit in the overall architecture of the project. Next is moving all that code to NH. But NH shoul offer full covergae. Half a year a ago this was not the case for 2008 and spatial data.

  • Paco

    Why don’t you use a proxy?
    Isn’t this violating the SRP?
    When you couple your entities with the lazy loading code, the entities are responsible of how they are loaded, shouldn’t that be somewhere else? You also have a problem when you want to load some things eager in one case and lazy in another.

    I don’t agree with your reasons not to use NHibernate.
    1. The learning time pays of.
    2. Not true, as mentioned earlier
    3. It’s probably cheaper to buy a server then to pay a developer to write the code.

  • Philipp C

    I agree that there is a lot of “static” in your code. Maybe you can use “constructor injection” to pass your delegates when you create the orders in the repo?

  • http://www.dotnettricks.com Fregas

    Well done. I ‘m at a place that seems to require stored procs for all data access, so I was wondering how to do DDD and PI w/o NHibernate. You’re solutions is along the same lines about what was floating around in my head.

    craig

  • http://petersgekko.codebetter.com/ pvanooijen

    Wow, thanks everybody for the richness of the comments.

    Some points:
    - Lazy loading is not just about collections. Note the Article property in the orderlines.

    - Eager loading may be better for some properties. The bas thing about my way of working that way is that it has to be decided by the domain class. Which is still smelly.

    - When you eager load the problem is what to load. Given the example it might be an idea to eager load all orderlines. But what about the articles ? Eager load them in the same query ? That will be a point where the mud starts. It requires a multitable join (not really the problem) but how to load the article object in the orderline ? And how to handle any lazy/eager properties in the article ? Suppose in the domain mode the article has a customers collection, describing all customers who eve bought this article. Etc, where will it end ?

    - For this project we have decided not to eager load anything but collections. Most collections are loaded in one shot (see the orderlines) but all entity properties are lazy loaded. In (sometimes many ) simple queries. And, as described, performance is quite OK It would be better to do some timing tests to investiigate it deeper.

    - In the example it looks somewhat silly to calculate the order total in the way described. But who says it is _the_ total :) Don’t take that to literally

    - If we are going to use an O-R mapper it will be nHibernate. I havn’t looked at nHibernate spatial yet. Sounds promissing. For now it is just a matter of presenting the team members simple straightforward sql and very little plumbing.

    - Doing anything with reflection is a non issue as it would introduce the same problem nHibernate itself has. Building anything towards a more serious framework doing O-R mapping “my-style” with “mystyle” proxies is imho the first step to hell. No way, as simple as possible, even simpler than this. Or else nHibernate.

  • http://thinkbeforecoding.com Think Before Coding

    I described a way to enable both lazy/eager loading with a light syntax in the following post :
    http://thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance
    This way, you can still use the object the same way when no lazy loading is needed, and you don’t need extra plumbing in your class (except declaring a Lazy instead of T for you lazy loaded field…)

  • http://www.joshjordan.com Josh Jordan

    True, it might not be the best example, but it definitely gets the point across. Thanks for the read!

  • http://www.tobinharris.com Tobin Harris

    Nice article. It’s fun to see how you tackled problems. I like the fact that the solutions are a fairly consistent and clean without too much ‘plumbing code’ everywhere. It’s also cool to remember that an ORM doesn’t *have* to be very complex.

    Have you considered selectively eager loading associated entities up-front rather than lazy loading? I find eager loading almost always performs better, and it makes the repository fully responsible for demarcating data access, which keeps things simple.

    Something like this was what I had in mind:

    // Using fetch strategy hints tells repository to eager-fetch required data
    var order = orders.GetOrder(10, OrderFetch.WithOrderLines)

  • http://blog.elliottohara.com Elliott

    I totally agree with what Andre said.

    Just because you don’t have NHibernate doesn’t mean you can’t use AOP to handle lazy loading, and it’s actually not much more work than what you’ve done here.

    In your example, you’ve made your model “aware” of lazy loading. Yeah, you’ve freed it of the implementation details of doing it, but you still have muddied the model with some delegate that has nothing to do with the actual entity.

    Would an “Order” ever “Request Order Lines”?

    So, the way I would handle this is move all the understanding of lazy loading out of you Order object into some other class (exactly like FluentNhibernate ClassMaps do), then you have your repos return proxies that consume those classes.

    Not much more work, and a clean domain.

    Just my $0.02
    Thanks for starting a great discussion!

  • http://magnusforsberg.wordpress.com Magnus Forsberg

    One thing that bothers me with your example is the iteration to calculate the grand total. To me, the Order feels like the aggregate root of the order lines and as such you would get the total cost from the order, not by iterating through it’s inner details. And by getting the total cost from the order, you can do an eager fetch for the order details as needed.

    Or did I miss something?

  • Bob

    If you are hesitant to jump into NHibernate (I am going through the same thing with my team), why not start with something like IBatis.NET? The learning curve is very minimal and you can use all of the hand-crafted SQL you desire. Things like lazy loading are supported out of the box.

  • Ryan

    Nice article. Have you looked into NHibernate.Spatial? I haven’t worked with it myself but will hopefully have the opportunity to look into it soon.

  • http://blog.andreloker.de Andre Loker

    The example you gave (calculating the grand total) is maybe not the best example where you want lazy loading. Depending on the number of order lines this will cause a lot of distinct queries (aka. the SELECT 1 + N problem). Fetching the data eagerly will most often be the more efficient solution.

    Regarding your implementation: honestly, that’s too much “static” for my taste. Static code is – well – static. You can’t use polymorphism or easily abstract from it with an interface. Especially, I find static code to be more difficult to test. You could instead use something like DynamicProxy to create proxy instances of your domain objects that implement lazy loading- just as NHibernate does.

    But then again – this still needs a lot of reflection and runtime code generaton, so it might not be an option for everyone. Maybe you could use PostSharp as a post compilation step to inject lazy loading. That should work in lower trust scanrios as well.

    Regards,
    Andre

  • obiwanjacobi

    I feel that the dependencies between LazyLoaders and the OrderRepository is “sub-optimal”. I would not depend the static ctor of the repository on LazyLoaders (maybe a factory to hook up the static callbacks?) and I would IoC the repository dependency in LazyLoaders, so other repository implementations can be injected (also for testing). But I understand its a sample, so you’re forgiven, but I had to say it ;-)

  • http://anothercodingcatastrophe.co.uk Nik Radford

    Typically when I’m doing data access I only do lazy loading on collections. Which I’ve created a class for, which takes an IEnumerable and populates itself from the IEnumerable when an action that requires the list to be enumerated is performed.

    Using the the love that is yield return you can keep it truly lazy, though I usually have to pull datasets so my my IEnumerable yield function (which I’m unaware what the actual name for them are) just builds the objects from the dataset(s) but you could do it with SqlDataReader if you don’t mind keeping a connection open to the database.

    Though for none collections I usually forego lazy loading.