Rabbi
Rabbi

Reputation: 4722

eager loading with dbcontext and projection

We are converting our project from ObjectContext to dbContext. Our current problem is with the difference in how eager loading is handled.

Example context

public class Person
{
    public virtual ICollection<Email> Emails { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}
public class Email
{
    public string Address{ get; set; }
}
public class Post
{
    public string Content{ get; set; }
}

we have many pieces of code throughout the enterprise that expect the emails to be loaded and therefore call person.Emails.First() without thinking about it. So we need to make sure that Emails are eagerly loaded.

Sometimes we can just us Include

However, when we use projections in our data layer we are running into problems. i.e.

return context.Persons.Select(p=> new Top5VM {
    Person = p,
    TopPosts = p.Posts.Take(5)
};

We have a lot of code that relies on Top5VM and expects Person.Emails to be loaded.

No mater what we've tried we can not figure out where to put the Include (or Load) function call where it will actually make a difference .

With the ObjectContext we would just have a dummy property on the Top5VM called Emails. Once that was loaded, the ObjectContext had references to all of those Entities an therefore never needed to go back to the server even when we accessed them through the person object. But that no longer works with the DbContext

Upvotes: 2

Views: 214

Answers (2)

Rabbi
Rabbi

Reputation: 4722

Figured it out. I need to set context.Configuration.LazyLoadingEnabled = false; any time I want to use projection to accomplish eager loading. Unless of course I want to access the loaded entities directly from the projection.

Upvotes: 1

John Castleman
John Castleman

Reputation: 1561

You can do this by always using your own DbContext in between:

public class MyDbContext : DbContext
{
    public MyDbContext() : base()
    {
        Configuration.LazyLoadingEnabled = false;
    }
}

Then use this everywhere instead of a DbContext.

Alternately, if you have control of all the POCOs, you could just remove the virtual keyword from the related collections ... the virtual keyword is the magic hookup Microsoft uses for lazy loading.

EDIT

I also tend to do this as an extension method:

static class DbContextExtensions
{
    public static DbContext AsEagerLoadingContext(this IDbContext context)
    {
        context.Configuration.LazyLoadingEnabled = false;
        //context.Configuration.AutoDetectChangesEnabled = false;

        return context;
    }
}

Used as so, allowing lazy loading to be used or not as needed:

using (var context = new DbContext().AsEagerLoadingContext())
    context.Stuff.Select(s => s.AllTheThings);

Upvotes: 0

Related Questions