Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.Recommendations)
    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.

like image 509
Drew Noakes Avatar asked Sep 08 '10 19:09

Drew Noakes


3 Answers

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

like image 135
DMac the Destroyer Avatar answered Oct 07 '22 21:10

DMac the Destroyer


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.

like image 44
Ladislav Mrnka Avatar answered Oct 07 '22 20:10

Ladislav Mrnka


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");
  }

}
like image 27
Marco Staffoli Avatar answered Oct 07 '22 21:10

Marco Staffoli