Home > Entity Framework, ORM > Addressing the pain of Entity Frameworks ObjectQuery<T>.Include()

Addressing the pain of Entity Frameworks ObjectQuery<T>.Include()

Well to be fair it’s not all the fault of .Include() alone, for me there is a real friction in the whole loading story in Entity Framework version 1 & 4 and it’s the direct result of the ‘fetching’ aspect of the API being fractured. For eager fetching we have:

ObjectQuery<T>.Include("Name.Your.Poison");

which goes for  both version 1.0 and 4.0. Many people take issue with this due to the magic string  alone.

For lazy loading we have two different mechanisms depending on which version of Entity Framework we are dealing with. Firstly in version 1.0 there is the unsightly :

ctx.Customers.First().Orders.IsLoaded;
ctx.Customers.First().Orders.Load();

and for version 4.0 we have the greatly appreciated improvement of :

ObjectContext.ContextOptions.LazyLoadingEnabled = true

Has Enough Changed?

However, despite this improvement it remains a fact that the two aspects of loading (lazy and eager) are from an API perspective, quite separate. I will cover how I plan to deal with this in Entity Framework 4.0 in a soon to follow series of posts.

Quite a while back I posted several times on how to achieve lazy loading with Entity Framework Version 1.0 with a framework I put together with the aid of PostSharp to weave some of its magic. It included a Repository, Specifications for strongly typed predicates for Query Builder methods and Fetching Strategies that instructed the framework which parts of an entities graph to lazily or eagerly fetch. As I said, the framework did include Fetching strategies however the framing of their design was targeted to that framework specifically and not general run of the mill Entity Framework usage. In the months since I keep coming upon different ways people (including Mattieu / Jamie / Julie) are trying to deal with the ObjectQuery<T>.Include() method, this prompted me to slim down the Fetching Strategy from my previous version and revisit it here for a more generalised usage in Entity Framework 1.0. Given the following entity model:

image

Using this model based on the venerable Northwind database, our usage might be something like:

static void Main(string[] args)
{
    var ctx = new NorthwindEntities();

    var fetch = new FetchingStrategy<Customer>();

    var orders = EagerFetchingIntention
        .CreateInstance<Customer, EntityCollection<Order>>(c => c.Orders);

    var orderLines = EagerFetchingIntention
        .CreateInstance<Order, EntityCollection<OrderLine>>(o => o.OrderLines);

    var combine = orders.And(orderLines);

    fetch.AddIntentions(new[]{combine});

    var custsWithOrdersAndLines = from c in ctx.Customers
                                            .WithFetchingStratey(fetch)
                                  select c;   

    foreach (var cust in custsWithOrdersAndLines)
    {
        Console.WriteLine(string.Format(“The customer ID is {0} and they “ +
            “have {1} orders with {2} order lines!”,
            cust.CustomerID, cust.Orders.Count(),
            cust.Orders.Sum(o => o.OrderLines.Count)));
    }
}
So we can see here from the compounding of multiple *fetching intentions* via the .And() method, we can drill into the entire graph of the root as we see fit. The WithFetchingStrategy extension method applies the generated .Includes() to the ObjectQuery. By abstracting the .Includes() away we can do interesting things such as loading the correct strategy from an IoC container based on the generic <T> argument.
I won’t repeat the code that makes up the Fetching Strategies here but I have provided a link to the code here for this new slimmed down version. As I said earlier, I have ways that I can work in both EF 1.0 and EF 4.0 that allow me to extend the idea of the fetching strategy to both lazy and eager loading (more on that and Entity Framework 4.0 soon), but I can’t say it wouldn’t be welcome if the Entity Framework provided that kind of apparatus itself out of the box.

Share/Save/Bookmark

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia