I am trying to filter three child levels down and find only child elements where PropertyMailingAddress.Status== True.
It is still returning values which are False unde
People tend to use Include as some kind of Shortcut for a Select. However, it is usually quite a waste of processing power to include all properties, because you won't use several of them or because you already know the value.
Take for instance a School with Students, a straightforward one-to-many relation. Every School has zero or more Students, every Student attends exactly one School, namely the School that the foreign key SchoolId refers to.
So if School [10] has 2000 Students, then every Student will have a value for SchoolId equal to 10. If you query School [10] with its Students, you will be transferring this value [10] more than 2000 times. What a waste of processing power!
In entity framework, use
Select
to query data, and only select the values that you actually plan to use. Only useInclude
if you plan to update the included data.
Certainly don't use Include as some kind of Shortcut for "Select all properties"!
Back to you question
You want to query (several properties of) all Properties, that have deep inside at least one PropertyMailingAddress with a true Status value.
Whenever you have a sequence of Items where every Item has a subsequence of OtherItems, and you want to investigate all OtherItems as if it were one sequence, consider using SelectMany:
var propertiesWithTrueStatus = propertyRepository.GetAll()
.Where(property => property.SelectMany(property => property.PropertyParties)
// result: one big sequence of all PropertyParties of all properties
.SelectMany(propertyParty => propertyParty.PartyMailingAddresses)
// result: one big sequence of all PartyMailingAddresses of all
// PropertyParties of all Properties
.SelectMany(partyMailingAddress => partyMailingAddress.PropertyMailingAddresses)
.Select(propertyMailingAddress => propertyMailingAddress.Status)
// result: one big sequence of all Statusses of all PropertyMailingAddresses
// of all ... of all Properties
// Keep only the true status values:
.Where(status => status)
// keep only the Properties that have at least one true Status value
.Any())
// end of Where(...)
So now you have only those Properties that deep inside have at least one true Status value. Continue the query with a Select
(or if you really want: Include
)
.Select(property => new
{
// Select only the properties that you actually plan to use
Id = property.Id,
Name = property.Name,
...
PropertyParties = property.PropertyParties.Select(propertyParty => new
{
// again only the properties that you plan to use:
Id = propertyParty.Id,
...
// no need to Select this, you already know the value
// PropertyId = propertyParty.PropertyId
PartyMailingAddresses = propertyParty.PartyMailingAddresses
.Select( partyMailingAddress => new { ... } )
.ToList(),
})
.ToList(),
});
Apart from that Select is more efficient than Include, it gives you more freedom to deviate from your database tables if needed. If you don't need all PropertyMailingAddresses in your end result, simply don't select them. If you only want the total number of PropertyParties, use PropertyPartyCount = propertyParties.Count
. With Select the returned data does not have to be similar to your database tables.
This has the advantage that you can hide changes in your database: simply change the Select, and all your users won't notice that deep inside you have changed your tables.