Reputation: 1936
I need to perform multi level Include()
query during EF Core select. I use AutoMapper with ProjectTo<>()
.
I have specified in mappings ExplicitExpansion()
which means navigation properties will not be populated automatically, because I want to have possibility to execute the same query multiple times and
one time Include()
navigation property but second time ignore it.
ProjectTo<>()
method has params which allows me to include navigation properties into my select, but I need to perform multi level include. Is this possible? Such syntax like Include(e => e.Collection.Select(sc => sc.MyProperty))
not working in this case.
I tried to use Include().ThenInclude()
for DbContext
and then perform ProjectTo
, but in that case ProjectTo
overrides my includes and they are ignored.
Now I'm not sure if that's possible at all to have ProjectTo
, ExplicitExpansion()
specified in mapping and have multi level include?
Upvotes: 6
Views: 6153
Reputation: 13823
I tried to use Include().ThenInclude() for DbContext and then perform ProjectTo, but in that case
ProjectTo
overrides my includes and they are ignored.
This overriding is working as intended.
Select()
overrides Include()
This is explicitly mentioned in the EF documentation:
If you change the query so that it no longer returns instances of the entity type that the query began with, then the include operators are ignored.
In the following example, the include operators are based on the
Blog
, but then theSelect
operator is used to change the query to return an anonymous type. In this case, the include operators have no effect.
Include
Include()
instructs EF to load some related entities when fetching the requested result set. This behavior is added to the default loading behavior of EF:
var people = db.People.ToList();
var peopleWithPets = db.People.Include(person => person.Pets).ToList();
By adding the Include()
, you've essentially expanded the loading behavior that happens under the hood when the collection is enumerated (in this case, ToList()
).
Select
Select()
overrides the default loading behavior with the new behavior you've defined.
var people = db.People.ToList();
var names = db.People.Select(person => person.Name).ToList();
When you call Select()
, you essentially instruct EF to not perform its default loading behavior (which may or may not entail additional includes), and instead load exactly what you have specified (in this case, person => person.Name
).
ProjectTo<>()
is a wrapper around Select()
You can think of ProjectTo<TDestination>()
as a sort of SelectFactory
which generates the appropriate Select
statement based on the TDestination
mapping that has been configured in Automapper.
Under the hood, EF still executes a Select()
, and therefore the same behavior as described above applies when using ProjectTo<>()
.
If you want to include additional related entities or any of their properties, you need to expand the Automapper mapping, as opposed to using Include
on the query. If your mapping includes additional fields, Automapper will expand its underlying Select()
accordingly.
Even if you had been able to include the related entities using Include
, Automapper would ignore them anyway if you never defined them as a mapping.
Upvotes: 8
Reputation: 1741
Did you try?
dbContext.Entities.ProjectTo<EntityDto>(dest => dest.Collection.Select(item => item.MyProperty));
Upvotes: 1