开发者

Entity Framework - Eager loading related entities

I'm using Entity Framework 4 with MVC and need to ensure any referenced entities I want to use in my view have been loaded before the controller method returns, otherwise the view spits out the dreaded:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

When selecting straight from the context, I can just use the Include(string) method to force them to be included in the generated SQL query:

var sellers = context.Sellers.Include("Recommendations.User").ToList();

However, if I have (for example) a helper method that accepts an entity and needs all items to be loaded, there's no Include method available.

void Test(Seller seller)
{
    // ensure all recommendations and their users are loaded
}

The brute force approach is to loop through them:

foreach (var recommendation in seller.Re开发者_Python百科commendations)
    recommendation.User.ToString(); // just force a load

If I have 100 recommendations, this will create 101 SQL queries behind-the-scenes. Ideally I want a method/approach that loads all Recommendation AND User objects with only a single trip to SQL.

Show me the money.

EDIT I'm not really interested in discussing whether this is a good or bad architecture. I've simplified my scenario for the sake of the question. Can you do what I'm asking with the EF API?

EDIT 2

Ladislav's edit offered hope of a new approach, but it seems I'm not quite there.

I can achieve what I want via this:

context.Sellers.Include("Recommendations.User").Single(s => s.Id == seller.Id);

This approach doesn't work using LoadProperty...

context.LoadProperty(seller, "Recommendations.User");

...as it fails with the error...

The specified navigation property Recommendations.User could not be found.

Neither of these approaches work if you don't have a reference to the context.


This is an old question, but in EF6 you can accomplish loading dependent objects on an entity like this:

context.Entry(seller).Collection(s => s.Recommendations).Query().Include(r => r.User)).Load();

That would load all Recommendations and their related Users for the given seller


I think this is a job for your repository which should in your case expose methods like GetFullSeller (all properties loaded by Include) and GetSeller (only base entity).

Edit:

There are several ways how to load navigation properties in EF v4.

  • Eager loading (using Include)
  • Lazy loading
  • Explicit loading by ObjectContext.LoadProperty (doesn't work for POCO)

There is no automatic loading.


I'm in the same situation. I think that with EF is very easy to fall in a 101 query problem.

A solution can be to create a partial class of your Seller class (generated by EF) and implement a GetSubclassNameQ that return a IQueryable, and a GetSubclassNameQFull that return a IQueryable with eager loading.

public partial class Seller{

  public IQueryable<Recommendation> GetRecommendationsQ(EntityContainer entitycontainer) {
    return entitycontainer.Recommendations;
  }      

  public IQueryable<Recommendation> GetRecommendationsQFull(EntityContainer entitycontainer) {
    return this.GetRecommendationsQ(entitycontainer).Include("Recommendations.User");
  }

  public IQueryable<Recommendation> GetRecommendationsQ() {
    return GetRecommendationsQ(new EntityContainer());
  }

  public IQueryable<Recommendation> GetRecommendationsQFull() {
    return this.GetRecommendationsQ().Include("Recommendations.User");
  }

}


Rather than passing your actual domain objects (EntityObjects) to the view, you may want to use your controller to map them into a Model object that better represents what your view should actually be displaying. This will reduce the amount of logic required in your View, and have the pleasant side-effect of avoiding passing EntityObjects around after their context has expired.

Edit based on your edit:

No, the API doesn't have a way to take a single Entity Object and make every other Entity Object of its type which was loaded at the same time it was be lazy-populated with a particular property in one fell swoop. You are better off pulling all of the items out in the first place using the Include mention like you show in your question.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜