I am working with Entity Framework code-first, and I have a class Course
which has a navigation property Students
:
public virtual Collection<Student> Students { get; set;}
It works ok, but as I access this navigation property, all the data is retrieved from the database:
var allStudents = course.Students; // Here it retrieves the data
var activeStudents = allStudents.Where(n => n.Active); // Here it filter the data on memory
var listOfActiveStudents = activeStudents.ToList(); // It already has the data on memory.
As you can imagine, I need the query to be executed when I do the .ToList()
because I don't want to bring all the Students
from the database, only the active ones.
Do you know what I am doing wrong?
use
dbContext.Entry( user ).Collection( u => u.Students ).Query()
to get anIQueryable<Student>
for the students collection navigation property, at which point you can add your filter and enumerate whenever you're ready for the dataOne workaround for this is to flip your query around, though it means avoiding using navigation properties in general. (Actual implementation will vary with your model.)
I prefer this to using the
Entry
method, since I use a general interface with my models and I don't want to expose EF6 types.Another way to avoid exposing EF6 types is to write a method like this:
Used something like this:
Lazy loading loads the entire set into memory. If you don't want that, switch lazy loading off by removing the
virtual
keyword and use the Query object on theDbEntry
:Is the "Active" flag an indicator that you are trying to implement soft delete? If so there is a solution here: Soft Delete in Entity Framework
You can vote for filtered includes here: Allow filtering for Include extension method
Another way to do it would be with inheritance. You could have an
ActiveStudent
inheriting fromStudent
and anActiveStudents
navigation property as well as anAllStudents
navigation property in theCourse
classReference:
Applying filters when explicitly loading related entities:
If you were to use proper variable typing then you would see what is happening. The entire set is lazy loaded loaded into memory by the navigation property.