Skip to content

Support for complex types projected via optional navigations #31412

Open

Description

We can support projecting complex types just fine, but projecting them via an optional navigation creates a problem:

public virtual Task Project_complex_type_via_optional_navigation(bool async)
    => AssertQuery(
        async,
        ss => ss.Set<CustomerGroup>().Select(cg => cg.OptionalCustomer!.ShippingAddress));

For cases where OptionalCustomer is null, EF currently materializes a non-null ShippingAddress with all-null values; it should be materializing null. The issue is that all we have are the ShippingAddress columns coming back from the database, and no way to know whether the address itself is null or not:

SELECT [c0].[ShippingAddress_AddressLine1], [c0].[ShippingAddress_AddressLine2], [c0].[ShippingAddress_ZipCode], [c0].[ShippingAddress_Country_Code], [c0].[ShippingAddress_Country_FullName]
FROM [CustomerGroup] AS [c]
LEFT JOIN [Customer] AS [c0] ON [c].[OptionalCustomerId] = [c0].[Id]

With e.g. owned entities this doesn't occur since the key columns of the owner entity type are projected as well (they're also the key columns of the owned entity type), and their nullability determines whether the owned is there or not.

The solution here would be to do a similar thing and project a single key property from the containing entity type, and then check that in the materializer to determine whether ShippingAddress should be null or not.

However, as @maumar pointed out, this is probably incompatible with Distinct: if we add the containing key column before the distinct, that effectively prevents DISTINCT from doing its job (since it's unique). We don't think there's a way to solve this in SQL (except maybe in PG where you can do DISTINCT BY 😉), so we should detect this and block it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions