Consider following LINQ query:
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select new
{
ItemProp1 = obj,
ItemProp2 = obj.NavProp2.Any(n => n.Active)
}).SingleOrDefault();
This runs as expected, but item.ItemProp1.NavProp1
is NULL.
As it explains here this is because of the query actually changes after using Include()
. but the question is what is the solution with this situation?
When I change the query like this, every things works fine:
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select obj).SingleOrDefault();
Regarding to this article I guess what the problem is... but the solution provided by author not working in my situation (because of using anonymous type in final select rather than entity type).
LINQ include helps out to include the related entities which loaded from the database. It allows retrieving the similar entities to be read from database in a same query. LINQ Include() which point towards similar entities must read from the database to get in a single query.
What is LINQKit? LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users. It comprises the following: An extensible implementation of AsExpandable() A public expression visitor base class (ExpressionVisitor)
Entity Framework Classic ThenIncludeThe ThenInclude method moves the chaining level to the property included. It allows us to include related objects from the next level. ThenInclude is a syntactic sugar method to make it easier and clearer to include multiple related objects.
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. C# Copy.
As you mentioned, Include
is only effective when the final result of the query consists of the entities that should include the Include
-d navigation properties.
So in this case Include
has effect:
var list = _db.SampleEntity.Include(s => s.NavProp1).ToList();
The SQL query will contain a JOIN
and each SampleEntity
will have its NavProp1
loaded.
In this case it has no effect:
var list = _db.SampleEntity.Include(s => s.NavProp1)
.Select(s => new { s })
.ToList();
The SQL query won't even contain a JOIN
, EF completely ignores the Include
.
If in the latter query you want the SampleEntity
s to contain their NavProp1
s you can do:
var list = _db.SampleEntity
.Select(s => new { s, s.NavProp1 })
.ToList();
Now Entity Framework has fetched SampleEntity
s and NavProp1
entities from the database separately, but it glues them together by a process called relationship fixup. As you see, the Include
is not necessary to make this happen.
However, if Navprop1
is a collection, you'll notice that...
var navprop1 = list.First().s.Navprop1;
...will still execute a query to fetch Navprop1
by lazy loading. Why is that?
While relationship fixup does fill Navprop1
properties, it doesn't mark them as loaded. This only happens when Include
loaded the properties. So now we have SampleEntity
all having their Navprop1
s, but you can't access them without triggering lazy loading. The only thing you can do to prevent this is
_db.Configuration.LazyLoadingEnabled = false;
var navprop1 = list.First().s.Navprop1;
(or by preventing lazy loading by disabling proxy creation or by not making Navprop1
virtual.)
Now you'll get Navprop1
without a new query.
For reference navigation properties this doesn't apply, lazy loading isn't triggered when it's enabled.
In Entity Framework core, things have changed drastically in this area. A query like _db.SampleEntity.Include(s => s.NavProp1).Select(s => new { s })
will now include NavProp1
in the end result. EF-core is smarter in looking for "Includable" entities in the end result. Therefore, we won't feel inclined to shape a query like Select(s => new { s, s.NavProp1 })
in order to populate the navigation property. Be aware though, that if we use such a query without Include
, lazy loading will still be triggered when s.NavProp1
is accessed.
I know this will probably get a few laughs, but don't forget the obvious like i just did. The row in the database didn't actually have a foreign key reference! I should have checked the dam data first before thinking EF Include wasn't working! Grrr. 30 minutes of my life I won't get back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With