Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Want Entity Framework 6.1 eager loading to load only first level

I am not sure I am approaching wrong way or it is a default behaviour but it is not working the way I am expecting ...

Here are two sample classes ...

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Department Department { get; set; }
}

Second one is Department

public class Department
{
    public string Name { get; set; }

    public List<Person> People { get; set; }
}

Context Configuration

public MyDbContext() : base("DefaultConnection") 
{
    this.Configuration.ProxyCreationEnabled = false;
    this.Configuration.LazyLoadingEnabled = false; 
}

public DbSet<Person> People { get; set; }
public DbSet<Department> Departments { get; set; }

I am try to load people where last name is from 'Smith'

var foundPeople 
        = context
              .people
              .Where(p => p.LastName == "Smith");

Above query load foundPeople with just FirstName and LastName no Department object. It is a correct behaviour as my LazyLoading is off. And that was expected as well.

Now in another query with Eager loading Department,

var foundPeople 
        = context
              .people
              .Where(p => p.LastName == "Smith")
              .Include(p => p.Department);

Above query loads foundPeople with FirstName, LastName, Department with Department->Name as well as Deparment->People (all people in that department, which I dont want, I just want to load first level of the Included property.

I dont know is this an intended behaviour or I have made some mistake.

Is there any way to just load first level of Included property rather then complete graph or all levels of included property.

like image 949
microchip78 Avatar asked Jun 04 '14 01:06

microchip78


People also ask

How do I set eager loading in Entity Framework?

Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load blogs and all the posts related to each blog. Include is an extension method in the System.

How do I enable lazy loading code first in Entity Framework?

Entity Framework : A Comprehensive Course Lazy loading means delaying the loading of related data, until you specifically request for it. When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook.

What is the difference between eager and lazy loading in Entity Framework?

While lazy loading delays the initialization of a resource, eager loading initializes or loads a resource as soon as the code is executed. Eager loading also involves pre-loading related entities referenced by a resource.

How do I turn off lazy loading in Entity Framework 6?

To turn off lazy loading for all entities in the context, set its configuration property to false.


Video Answer


2 Answers

Using Include() to achieve eager loading only works if lazy loading is enabled on your objects--that is, your navigation properties must be declared as virtual, so that the EF proxies can override them with the lazy-loading behavior. Otherwise, they will eagerly load automatically and the Include() will have no effect.

Once you declare Person.Department and Department.People as virtual properties, your code should work as expected.

Very sorry, my original answer was wholly incorrect in the main. I didn't read your question closely enough and was incorrect in fact on the eager behavior. Not sure what I was thinking (or who upvoted?). Real answer below the fold:


Using the example model you posted (with necessary modifications: keys for the entities and removed "this" from context constructor) I was unable to exactly reproduce your issue. But I don't think it's doing what you think it's doing.

When you eagerly load the Department (or explicitly load, using context.Entry(...).Reference(...).Load()) inspect your results more closely: there are elements in the Department.People collections, but not all the Persons, only the Persons that were loaded in the query itself. I think you'll find, on your last snippet, that !foundPeople.SelectMany(p => p.Department.People).Any(p => p.LastName != "Smith") == true. That is, none of them are not "Smith".

I don't think there's any way around this. Entity Framework isn't explicitly or eagerly loading People collections (you could Include(p => p.Department.People) for that). It's just linking the ones that were loaded to their related object, because of the circular relationship in the model. Further, if there are multiple queries on the same context that load other Persons, they will also be linked into the object graph.

(An aside: in this simplified case, the proxy-creation and lazy-loading configurations are superfluous--neither are enabled on the entities by virtue of the fact that neither have lazy or proxy-able (virtual) properties--the one thing I did get right the first time around.)

like image 196
Marc L. Avatar answered Oct 13 '22 06:10

Marc L.


By desing, DbContext does what it's called "relationship fix-up". As your model has information on which are the relations between your entities, whenever an entity is attached, or modified, in the context, EF will try to "fix-up" the relations between entities.

For example, if you load in the context an entity with a FK that indicates that it's a children of another entity already attached to the context, it will be added to the children collection of the existing entity. If you make any chages (change FK, delete entity, etc.) the relationships will be automatically fixed up. That's what the other answer explains: even if you load the related entities separatedly, with a different query, they'll be attached to the children collection they belong to.

This functionality cannot be disabled. See other questions related to this:

  • AsNoTracking and Relationship Fix-Up
  • Is it possible to enable relationship fixup when change tracking is disabled but proxies are generated

How to get rid of the related entities

I don't know what you need to do, but with the current version of EF you have to detach the entity from the context and manually remove the related entities.

Another option is to map using AutoMapper or ValueInjecter, to get rid of the relationship fix-up.

like image 38
JotaBe Avatar answered Oct 13 '22 06:10

JotaBe