One of the additions to NCommon I haven’t blogged about yet is an implementation of a fetching strategy in NCommon

First a brief background on Lazy / Deferred Loading:

Most ORM’s provide a concept called lazy loading of related entities. The concept of lazy loading should be well known but if you’re unfamiliar with it here’s a brief overview. Lazy loading, a.k.a deferred loading, is the concept of loading associated entities from the database at the time of access.

Meaning that say you have an Order object that has a list of OrderItem entities that represent the items being ordered. When you load the Order entity, the OrderItems associated with those entities are not loaded as well. Only when you access the property of the Order entity that exposes the OrderItems property will the entity then go to the database and fetch items OrderItems.

The advantage of lazy loading is that you don’t load the entire object graph at the time the aggregate root entity is loaded. Take for example a Customer object normally has a list of Orders association, represented maybe by a ICollection<Order> Orders property. If you just want to read the contact information of the Customer entity, you don’t really need to load all the Orders of the customer as well. So lazy loading helps by just retrieving the Customer record from the database, and when and if you require the Orders collection of the Customer entity, a query will be made at that time to load the list of orders.

The need for a Fetching Strategy:

Most of the times Lazy / Deferred Loading is a real advantage, but it can also be a performance nightmare in certain scenarios. Take for example the model below:

Model

The model is pretty straight forward. There is a Customer class that holds a collection association to Order entities representing all the orders for a Customer. There’s a Order class that holds a reference to the Customer for which this order was generated and a collection association of OrderItem instances representing the items being ordered. Each OrderItem in turn has a reference to a Product entity that represents the product being ordered.

Lets say you were to now to show a list of all products (unique) that has been ordered and shipped by a customer within a 2 month period.

public HashSet<Product> ProductsOrdered(Customer customer, int months)

{

    var productsOrdered = new HashSet<Product>();

    var orders = from order in _ordersRepository

                 where order.Customer == customer &&

                       (order.ShipDate >= DateTime.Now.AddMonths(-months) &&

                        order.ShipDate <= DateTime.Now.Date)

                 select order;

 

    foreach (var order in orders)

        foreach (var orderItem in order.Items)

            productsOrdered.Add(orderItem.Product);

 

    return productsOrdered;

}

What the above code is going to do is first fetch all the orders for the specified customer that has a ship date between that 2 months window. Next at every iteration of an order, it’s items will be loaded from the database and for each OrderItem, the associated product will be loaded.

So if the customer has 10 orders, each with 10 order items and each order item referencing a unique product, that would result in 111 queries to the database to get the result.

That's a colossal waste of resources.

So what is a fetching strategy anyway?

A fetching strategy simply put allows you to define at the time of loading the aggregate root, what all associated entities will also be queried for and loaded in the object graph. The fetching strategy is an explicit pattern which tells the ORM framework to pre-fetch objects within the graph and not perform lazy loading for the entities specified in the strategy.

Defining a fetching strategy would allow us to specify that the data required for the above code to work should be fetching in one single query to the database. That allows efficient use of the database resources as well as avoiding round trips back to the database.

Fetching strategies and Adaptive Domain models:

Fetching strategies normally are not static, and based on the context your code is operating under you would want to use different fetching strategies. For example in the above code snippet that gets all the products shipped to a customer, you would want to define a fetching strategy that gets the entire object graph of Order, it’s OrderItems and each OrderItem’s referenced Product entity.

Lets say someplace else in your application you want to calculate the sum total of all orders placed within the last two months for a customer.

public float TotalOrderAmount(Customer customer, int months)

{

    float totalAmount = 0;

    var orders = from order in _ordersRepository

                 where order.Customer == customer &&

                       (order.ShipDate >= DateTime.Now.AddMonths(-months) &&

                        order.ShipDate <= DateTime.Now.Date)

                 select order;

 

    foreach (var order in orders)

        foreach (var orderItem in order.Items)

            totalAmount += orderItem.Total;

 

    return totalAmount;

}

Very similar to the first example, but this one doesn’t require the OrderItem’s associated Product references to be pre-fetched. (I know the correct way to calculate the total value for an order would be to have a TotalValue() method on the order that iterates the Items internally and sums up the total. I needed to be explicit in this example to show the graph that was accessed)

This is somewhat the basis of an adaptive domain model where the fetching strategy for domain entities are based on the current execution context. A lot has been talked about on Adaptive Domain models by Udi Dahan here and here and even Oren Eini (Ayende) here. I suggest you take a look at their posts, if you haven’t already.

Fetching strategy in NCommon

If you’ve note read the posts (links above) by Udi and Oren, I would urge you to do so because what follows relies heavily on the assumption that you have read and understood fetching strategies and the solutions proposed by Udi and Oren.

Okay, so let me start by saying that I agree 100% with Udi and Oren on their implementation of how fetching strategies are defined. That being said, in NCommon there is a slight modification of how fetching strategies are defined and consumed by the framework. The difference is in how the repository is configured to use fetching strategies.

In Udi’s implementation, a repository is created to return IOrderCalculator instances, which is implemented by the Order entity (or can be implemented by a completely different entity) and based on that the repository will auto configure what ever fetching strategies are defined for an IOrderCalculator.

I don’t necessary like that approach is because, a) additional configuration/mappings need to be defined to allow the repository to return IOrderCalculator instances, b) the service is now working with IOrderCalculator instances rather than Order instances (even though Order implements IOrderCalculator).

What I would really like is to have the repository instances return Order instnaces which are configured with fetching strategies for IOrderCalculator. That’s where NCommon differs from the above fetching strategy design.

In NCommon, the IFetchingStrategy interface, used to define a fetching strategy, looks like this:

///<summary>

/// Specifies a fetching strategy for a <see cref="IRepository{TEntity}"/> instance.

///</summary>

public interface IFetchingStrategy<TEntity, TForService>

{

    ///<summary>

    /// Instructs the instance to define the fetching strategy on the repository instance.

    ///</summary>

    ///<param name="repository"></param>

    void Define(IRepository<TEntity> repository);

}

There’s just one Define method to which the repository instance is passed that the fetching strategy should configure. Below are examples of fetching strategies; one defined for IOrderCalculator and one for IOrderProductListing, both are defined for configuring a repository that returns Order entities:

public class OrderCalculatorStrategy : IFetchingStrategy<Order, IOrderCalcualtor>

{

    #region Implementation of IFetchingStrategy<Order,IOrderCalcualtor>

    ///<summary>

    /// Instructs the instance to define the fetching strategy on the repository instance.

    ///</summary>

    ///<param name="repository"></param>

    public void Define(IRepository<Order> repository)

    {

        repository.With(x => x.Items);

    }

    #endregion

}

 

 

 

public class OrderProductListingStrategy : IFetchingStrategy<Order, IOrderProductLister>

{

    #region Implementation of IFetchingStrategy<Order,IOrderProductLister>

    ///<summary>

    /// Instructs the instance to define the fetching strategy on the repository instance.

    ///</summary>

    ///<param name="repository"></param>

    public void Define(IRepository<Order> repository)

    {

        repository.With(x => x.Items);

        repository.With<OrderItem>(x => x.Product);

    }

    #endregion

}

Here are the IOrderCalculator and IOrderProductLister interfaces

public interface IOrderCalcualtor

{

    decimal GetTotalValue();

}

 

public interface IOrderProductLister

{

    ICollection<Product> ListOrderedProducts();

}

Now I can implement these interfaces on either the domain entities or on domain services. For example, the Order entity implements the IOrderCalculator interface to provide the total value of the order and a OrdersService domain service implements the IOrderProductLister interface to provide the logic of listing all products ordered by a customer for the last x number of months.

So now that I have my fetching strategies defined and defined the context that specifies what strategy (or strategies as there could be multiple) are to be used, the next is how to instruct the repository to use what fetching strategy. This is done by calling the For method on the IRepository instance.

public HashSet<Product> ListOrderedProducts(Customer customer, int months)

{

    var productsOrdered = new HashSet<Product>();

    var orders = from order in _ordersRepository.For<IOrderProductLister>()

                 where order.Customer == customer &&

                       (order.ShipDate >= DateTime.Now.AddMonths(-months) &&

                        order.ShipDate <= DateTime.Now.Date)

                 select order;

 

    foreach (var order in orders)

        foreach (var orderItem in order.Items)

            productsOrdered.Add(orderItem.Product);

 

    return productsOrdered;

}

 

 

 

public decimal GetTotalOrderAmount(Customer customer, int months)

{

    decimal totalAmount = 0;

    var orders = from order in _ordersRepository.For<IOrderCalcualtor>()

                 where order.Customer == customer &&

                       (order.ShipDate >= DateTime.Now.AddMonths(-months) &&

                        order.ShipDate <= DateTime.Now.Date)

                 select order;

 

    foreach (var order in orders)

        totalAmount += order.GetTotalValue();

 

    return totalAmount;

}

In the ListOrderedProducts method, the repository is configured to use the fetching strategies defined for IOrderProductLister for the Order entity, and in the second case the GetTotalOrderAmount instructs the repository to use all fetching strategies defined for the IOrderCalculator interface.

The For method is implemented by the abstract RepositoryBase base class which allows all implementations that inherit from RepositoryBase to automatically take advantage this fetching strategy pattern. In the For method implementation in RepositoryBase, it simply attemps to resolve all IFetchingStrategy instances defined for the domain entity and the specified context. Then in a tight loop calls the Define method on each strategy found by passing itself as the repository instance.

/// <summary>

/// Defines the service context under which the repository will execute.

/// </summary>

/// <typeparam name="TService">The service type that defines the context of the repository.</typeparam>

/// <returns>The same <see cref="IRepository{TEntity}"/> instance.</returns>

/// <remarks>

/// Gets all fetching strategies define for a service for the current type and configures the

/// repository to use that fetching strategy.

/// </remarks>

public IRepository<TEntity> For<TService>()

{

    var strategies = ServiceLocator.Current

            .GetAllInstances<IFetchingStrategy<TEntity, TService>>();

    if (strategies != null && strategies.Count() > 0)

        strategies.ForEach(x => x.Define(this));

    return this;

}

And thats about it. This way I get the flexibility of defining my context interfaces, which are the IOrderCalculator and IOrderProductLister, on either the domain entity or domain services while still maintaining one mapping configuration for my domain entities and working directly with my domain model.

Posted on Wednesday, February 11, 2009 8:00 PM | Filed Under [ NCommon Patterns DDD Repository ]


Comments

Gravatar
# Implementing the FetchingStrategy using NCommon 1....
Posted by Gerhard Sommer
on 3/17/2010 7:18 PM
Implementing the FetchingStrategy using NCommon 1.1 was very helpful for me. It is a very useful pattern.

But I have the following object hierarchy:

class A has property BMap, that is of type IDictionary{B}

class B has property CList, that is of type IList{C}

How can I achieve eager fetching in this case?

If I access CList, NHibernate fetches the data internally, so defining a FetchingStrategy for a Repository{B} does not help, as NHibernate does not use the repository to fetch the data.

I only want to fetch instances of type A using a Repository{A} and then access the child objects using the properties.

I used the workaround to implement a FetchingStrategy for Repository{B} and used this to eager load all B instances, that belong to A (there is a reference to the parent in B).

But I don't really like this solution. I would prefer to be able to eager load all children of A at once.
Gravatar
# As usual good introduction to a topic backed by so...
Posted by JG
on 2/12/2009 8:59 AM
As usual good introduction to a topic backed by solid examples, nice..
Gravatar
# re: Fetching strategy and adaptive domain models in NCommon
Posted by replica watches
on 11/9/2011 2:36 AM
nice post...
Gravatar
# re: Fetching strategy and adaptive domain models in NCommon
Posted by Ugg boots
on 12/26/2011 2:05 AM
thanks for sharing...
Gravatar
# Mrs
on 12/28/2011 3:49 AM
Gravatar
# re: Fetching strategy and adaptive domain models in NCommon
Posted by mulberry outlet
on 3/7/2012 5:39 AM
This approach offers a pointy comparability with a bit of designer manufacturers while internatinal bag handbagMulberry fairy bag contains a extensive patiently waiting check list.
Gravatar
# re: Fetching strategy and adaptive domain models in NCommon
Posted by FranciscoRios
on 3/21/2012 11:04 PM
Post Comment
Title *
Name *
Email
Url
Comment *  
Please add 8 and 3 and type the answer here: