Filtering On ThenInclude Three Nested Levels down

前端 未结 1 948
一整个雨季
一整个雨季 2021-01-23 12:49

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

1条回答
  •  有刺的猬
    2021-01-23 13:16

    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 use Include 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

    • Every Property has zero or more PropertyParties.
    • Every PropertyParty has zero or more Properties.
    • Every Property has zero or more PartyMailingAddresses
    • Every PartyMailingAddress has zero or more PropertyMailingAddresses
    • Every PropertyMailingAddress has a Boolean property Status

    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.

    0 讨论(0)
提交回复
热议问题