简体   繁体   中英

EF5 ObjectContext : How to replace IQueryable<T>.Include(Path) with context.T.Attach()

I'm using Entity Framework 5 with ObjectContext on a relatively big and complex data model. I would like to work around big queries generated when chaining multiple IQueryable.Include(Path) to eager load related objects.

For example, I'm doing something like this :

var queryPe = context.Person.Where(p => p.Id == 110).Include(@"AA");
queryPe = queryPe.Include(@"BB.CC.DD");
queryPe = queryPe.Include(@"EE.FF");

It could be made generic by using a string array and chaining each graph at runtime in a foreach loop.

Instead, I would like to do something like this :

Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
pe.BB.Attach(pe.BB.CreateSourceQuery().Include(@"CC.DD"));
pe.EE.Attach(pe.EE.CreateSourceQuery().Include(@"FF"));

Instead of having one big query we would have 4 smaller queries hitting the database. Of course I still want to leverage the power of the graph path as a string.

I may be wrong, but this means that I should use relexion to get the navigation properties by name and executing the CreateSourceQuery() on it because there is no such extension method to do this.

Am I correct ?

EDIT 1 : Well, I have an additionnal constraint, that is, I'm using Self Tracking Entities (STE). This means that Related objects are not materialized as EntityCollection or EntityReference. So Attach() and CreateSourceQuery() are not available !

So I'm stuck with Context.LoadProperty to deal with object graphs. Is it only possible ?

EDIT 2 : Problem exposed in EDIT 1 solved, thanks to the help of DbContext class. See the code below :

Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
DbContext dbc = new DbContext(context, false);
dbc.Entry(pe).Collection(@"BB").Query().Include(@"CC.DD").Load();
dbc.Entry(pe).Reference(@"EE").Query().Include(@"FF").Load();

EDIT 3 02/11/2013 : There is an issue with the code presented above (EDIT 2). If the last entity in the path is a reference and not a collection, the code doesn't fail but it is not loaded :-(

EDIT 4 : Instead of using reflection, right now, I'm generating the code by looking at the Entity Data Model with the help of a T4 template.

Sometimes stored procedures are best. Write a stored procedure that returns multiple result sets, one for each type of entity you wish to eagerly load. This is highly performant compared to what you're trying to accomplish and the stored procedure will be far more readable than this jumble of includes and separate load statements per reference/collection. And yes, EF will hook up related entities automatically!

Here's a reference for sprocs with multiple result sets for both EDMX and code first:

http://msdn.microsoft.com/en-us/data/jj691402.aspx

Try to separate your aggregates in multiple contexts. Each Bounded context should have a separate context. This way you create a loosely coupled entity framework solution.

Julie Lerman has a good video on plural sight about this concept.

I would prefer to use stored procedures. Easy maintainance, works faster etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM