IC窗口
community.icburner.com
What about DataLoadOptions for Entity Framework ObjectContext?

What about DataLoadOptions for Entity Framework ObjectContext?

I think the proper way to start this post is to ask How do you do eager loading with Entity Framework? And the basic native simple answer is by using ObjectQuery<T>.Include(string) method. No matter what you tried to do, you’ll end up using this way.

So there was ideas about how enhance the eager loading in our Entity Framework base applications. You can read about some of these ideas:

As I said, no matter what you tried, you’ll end up using ObjectQuery<T>.Include(string).

My Proposal:

I am here now to propose my idea. And I am just proposing. What about DataLoadOptions for Entity Framework ObjectContext?! Do You know DataLoadOptions class in Linq to Sql?! Yes, I want to steal the idea and make it fit for Entity Framework. I want to implement a tiny clone of DataLoadOptions for Entity Framework. This would give you an option similar to this:

1. var context = new NorthwindObjectContext;   

2. var loadOptions = new DataLoadOptions()   

3. DataLoadOptions.LoadWith<Product>(p=>p.Category)   

4. DataLoadOptions.LoadWith<Product>(p=>p.Supplier)   

5.

6. context.LoadOptions = loadOptions;   

7.

8. var products = context.ProductsSet;  

var context = new NorthwindObjectContext;

var loadOptions = new DataLoadOptions()

DataLoadOptions.LoadWith<Product>(p=>p.Category)

DataLoadOptions.LoadWith<Product>(p=>p.Supplier)

context.LoadOptions = loadOptions;

var products = context.ProductsSet;

Of course this is not going to work by itself. The above is a usage sample, however the implementation of such feature will require some coding, and guess what, I’ll end up using ObjectQuery<T>.Include(string).

Where did I reach?

I am almost done with this idea! The DataLoadOptions class for EF is completed with tests. It worth to mention that this class is not 100% clone of LINQ to SQL DataLoadOptions one! There is a big difference. And I can say for some reason in EF you will not fall in mistakes like cyclic issues (read about it on DataLoadOptions remarks section) for example in LINQ to SQL you cannot do this:

1. loadOptions.LoadWith<Product>(p=>p.Category);   

2. loadOptions.LoadWith<Category>(c=>c.Products);  

loadOptions.LoadWith<Product>(p=>p.Category);

loadOptions.LoadWith<Category>(c=>c.Products);

But in EF it would be safe because you can control implicitly.

Conclusion:

I hope soon I’ll be able to present a demo code. But for now I can say it will be as reusable code that you’ll have to customize to attache to your EF implementation. I am currently integrating it into KiGG as part of EF flavour of repository on KiGG. At the moment I am writing this post I didn’t comment it to KiGG source control. So keep tuned.

Introducing DataLoadOptions for Entity Framework ObjectContext

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:

  1. 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.
  2. I should provide my ObjectContext with a DataLoadOptions instance:
    context.LoadOptions = dataLoadOptions;
  3. Before trying to retrieve any EntitySet (context.ProductSet) I should start prepare the query to include all registered preloaded members using ObjectContext.Include method.

1. public partial class NorthwindObjectContext: ObjectContext   

2. {   

3. public ObjectQuery<Product> ProductSet   

4.   {   

5. get

6.         {   

7. if (_productSet==null)   

8.             {   

9.                 _productSet  = ApplyDataLoadOptions<Product>("ProductSet");   

10.             }   

11. return _productSet;   

12.         }   

13.     }   

14.

15. private ObjectQuery<TEntity> ApplyDataLoadOptions<TEntity>(string queryString)   

16.     {   

17.         var query = CreateQuery<TEntity>(queryString);   

18.

19. if (LoadOptions != null)   

20.         {   

21.             var members = LoadOptions.GetPreloadedMembers<TEntity>();   

22.

23. foreach (var member in members)   

24.             {   

25.                 query = query.Include(member.Name);   

26.             }   

27.         }   

28. return query;   

29.     }   

30. }  

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:

1. using(var context = new NorthwindObjectContext())   

2. {   

3.     var loadOptions = new DataLoadOptions();   

4.     loadOptions.LoadWith<Product>(p => p.Category);   

5.     loadOptions.LoadWith<Product>(p => p.Supplier);   

6.

7.     context.LoadOptions = loadOptions;   

8.

9.     var queryString = context.ProductSet.ToTraceString();   

10.         var products = context.ProductSet;   

11. foreach(var product in products)   

12.         {   

13.             Console.WriteLine(product.Category.Name);   

14.         }   

15.     Console.WriteLine(queryString);   

16. }  

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:

1. loadOptions.LoadWith<Product>(p=>p.Category);     

2. loadOptions.LoadWith<Category>(c=>c.Products);   

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


Posted 2009/6/16 1:31 by 革命
Filed under: