Want Entity Framework 6.1 eager loading to load only first level
Asked Answered
C

3

6

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.

Chardin answered 4/6, 2014 at 1:57 Comment(0)
U
3

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

Utrecht answered 4/6, 2014 at 2:46 Comment(0)
M
2

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:

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.

Monophonic answered 10/6, 2014 at 9:54 Comment(0)
F
-2

You could try using a LINQ query so you can select only the fields that you need. I hope that helps.

Fibrinolysis answered 4/6, 2014 at 2:1 Comment(2)
I see. but as far as I know, that's the default behaviour of EF. That is why LINQ is there in case you want to get specific properties without spending much memory loading un-necessary properties.Fibrinolysis
The same behavior is accessible with extension methods, using Select(e => new {...});. This answer seems to miss the crux of the question.Utrecht

© 2022 - 2024 — McMap. All rights reserved.