On my previous post “What about DataLoadOptions for Entity Framework ObjectContext?” I was suggesting another way to define eager loading for Entity Framework. In this post I will introduce my DataLoadOptions for Entity Framework ObjectContext.
The beginning:
Actually Eager and Lazy loading on Entity Framework is not that much fun like in Linq to Sql. However this is going to be improved in EF4.
Here I will focus on eager loading and my slight improvement to define eager loading in Entity Framework. When I start to think about, I wanted something simple and pretty close to the way Linq to Sql work. In Linq to Sql it is the DataLoadOptions that helps you define eager loading before start using Linq to Sql DataContext.
So I started to explore the DataLoadOptions code using reflector, to better understand how it works and how it helps Linq to Sql define eager loading.
The Idea:
The idea was very simple here it is:
- First I need to register the entity members that I wish to pre load when retrieving root entity. This should be achieved with this syntax dataLoadOptions.LoadWith<Product>(p=>p.Category). My DataLoadOptions should store that I want to pre load product’s category whenever I attempt to load a product record.
- I should provide my ObjectContext with a DataLoadOptions instance:
context.LoadOptions = dataLoadOptions; - Before trying to retrieve any EntitySet (context.ProductSet) I should start prepare the query to include all registered preloaded members using ObjectContext.Include method.
public partial class NorthwindObjectContext: ObjectContext
{
public ObjectQuery<Product> ProductSet
{
get
{
if (_productSet==null)
{
_productSet = ApplyDataLoadOptions<Product>("ProductSet");
}
return _productSet;
}
}
private ObjectQuery<TEntity> ApplyDataLoadOptions<TEntity>(string queryString)
{
var query = CreateQuery<TEntity>(queryString);
if (LoadOptions != null)
{
var members = LoadOptions.GetPreloadedMembers<TEntity>();
foreach (var member in members)
{
query = query.Include(member.Name);
}
}
return query;
}
}
You should know that this idea is close the one in Linq to Sql but it is not exactly the same.
Implementation:
I had attached a sample code to this post that include the implementation of DataLoadOptions class, to save space I will let that to you to explore.
Part of the implementation is to have ApplyDataLoadOptions method (or call it whatever you want) as in line 15 above. This method is using GerPreloadedMembers<TEntity> method of DataLoadOptions instance to get all registered properties for eager loading. Then it loops through those members and call Include method passing member/property name, finally found a good usage of having Include method accepting string.
Here is a sample usage code:
using(var context = new NorthwindObjectContext())
{
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Product>(p => p.Category);
loadOptions.LoadWith<Product>(p => p.Supplier);
context.LoadOptions = loadOptions;
var queryString = context.ProductSet.ToTraceString();
var products = context.ProductSet;
foreach(var product in products)
{
Console.WriteLine(product.Category.Name);
}
Console.WriteLine(queryString);
}
Hints:
The following is not allowed in Linq to Sql:
loadOptions.LoadWith<Product>(p=>p.Category);
loadOptions.LoadWith<Category>(c=>c.Products);
This should throw an exception. In Entity Framework this is not the case it will work. Not because this implementation is much better than the on in Linq to Sql, but because it is different and work differently than Linq to Sql.
Conclusion:
EF4 is promising, and I highly recommend that you keep tuned about what ADO.NET on Entity Framework doing. So far I didn’t read about what they are going to provide for Eager Loading, but I expect that soon.
I have plugged this implementation of DataLoadOptions into KiGG EF implementation. I wanted to keep both Linq to Sql And Entity Framework implementations on KiGG as close as possible. I’ve tested it and I guess it is stable enough to be used in production.
Sample Download
You comments and suggestions are appreciated.