protected Expression ExpandNavigation(
                Expression root, EntityReference entityReference, INavigation navigation, bool derivedTypeConversion)
            {
                if (entityReference.NavigationMap.TryGetValue(navigation, out var expansion))
                {
                    return(expansion);
                }

                if (navigation.GetTargetType().IsOwned())
                {
                    var ownedEntityReference = new EntityReference(navigation.GetTargetType());
                    ownedEntityReference.MarkAsOptional();
                    if (entityReference.IncludePaths.ContainsKey(navigation))
                    {
                        ownedEntityReference.SetIncludePaths(entityReference.IncludePaths[navigation]);
                    }

                    var ownedExpansion = new OwnedNavigationReference(root, navigation, ownedEntityReference);
                    if (navigation.IsCollection())
                    {
                        return(new MaterializeCollectionNavigationExpression(ownedExpansion, navigation));
                    }
                    else
                    {
                        entityReference.NavigationMap[navigation] = ownedExpansion;
                        return(ownedExpansion);
                    }
                }

                var innerQueryableType = navigation.GetTargetType().ClrType;
                var innerQueryable     = NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(innerQueryableType);
                var innerSource        = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable);

                if (entityReference.IncludePaths.ContainsKey(navigation))
                {
                    var innerIncludeTreeNode = entityReference.IncludePaths[navigation];
                    var innerEntityReference = (EntityReference)((NavigationTreeExpression)innerSource.PendingSelector).Value;
                    innerEntityReference.SetIncludePaths(innerIncludeTreeNode);
                }

                var        innerParameter = Expression.Parameter(innerSource.SourceElementType, "i");
                Expression outerKey;

                if (root is NavigationExpansionExpression innerNavigationExpansionExpression &&
                    innerNavigationExpansionExpression.CardinalityReducingGenericMethodInfo != null)
                {
                    // This is FirstOrDefault ending so we need to push down properties.
                    var temporaryParameter = Expression.Parameter(root.Type);
                    var temporaryKey       = CreateKeyAccessExpression(temporaryParameter,
                                                                       navigation.IsDependentToPrincipal()
                            ? navigation.ForeignKey.Properties
                            : navigation.ForeignKey.PrincipalKey.Properties);
                    var newSelector = ReplacingExpressionVisitor.Replace(
                        temporaryParameter,
                        innerNavigationExpansionExpression.PendingSelector,
                        temporaryKey);
                    innerNavigationExpansionExpression.ApplySelector(newSelector);
                    outerKey = innerNavigationExpansionExpression;
                }
            protected Expression ExpandNavigation(
                Expression root, EntityReference entityReference, INavigation navigation, bool derivedTypeConversion)
            {
                if (entityReference.NavigationMap.TryGetValue(navigation, out var expansion))
                {
                    return(expansion);
                }

                var targetType = navigation.TargetEntityType;

                if (targetType.HasDefiningNavigation() ||
                    targetType.IsOwned())
                {
                    var ownedEntityReference = new EntityReference(targetType);
                    ownedEntityReference.MarkAsOptional();
                    if (entityReference.IncludePaths.ContainsKey(navigation))
                    {
                        ownedEntityReference.SetIncludePaths(entityReference.IncludePaths[navigation]);
                    }

                    var ownedExpansion = new OwnedNavigationReference(root, navigation, ownedEntityReference);
                    if (navigation.IsCollection)
                    {
                        var elementType = ownedExpansion.Type.TryGetSequenceType();
                        var subquery    = Expression.Call(
                            QueryableMethods.AsQueryable.MakeGenericMethod(elementType),
                            ownedExpansion);

                        return(new MaterializeCollectionNavigationExpression(subquery, navigation));
                    }

                    entityReference.NavigationMap[navigation] = ownedExpansion;
                    return(ownedExpansion);
                }

                var innerQueryable = new QueryRootExpression(targetType);
                var innerSource    = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable);

                if (entityReference.IncludePaths.ContainsKey(navigation))
                {
                    var innerEntityReference = (EntityReference)((NavigationTreeExpression)innerSource.PendingSelector).Value;
                    innerEntityReference.SetIncludePaths(entityReference.IncludePaths[navigation]);
                }

                var        innerSourceSequenceType = innerSource.Type.GetSequenceType();
                var        innerParameter          = Expression.Parameter(innerSourceSequenceType, "i");
                Expression outerKey;

                if (root is NavigationExpansionExpression innerNavigationExpansionExpression &&
                    innerNavigationExpansionExpression.CardinalityReducingGenericMethodInfo != null)
                {
                    // This is FirstOrDefault ending so we need to push down properties.
                    var temporaryParameter = Expression.Parameter(root.Type);
                    var temporaryKey       = temporaryParameter.CreateKeyValuesExpression(
                        navigation.IsOnDependent
                            ? navigation.ForeignKey.Properties
                            : navigation.ForeignKey.PrincipalKey.Properties,
                        makeNullable: true);
                    var newSelector = ReplacingExpressionVisitor.Replace(
                        temporaryParameter,
                        innerNavigationExpansionExpression.PendingSelector,
                        temporaryKey);
                    innerNavigationExpansionExpression.ApplySelector(newSelector);
                    outerKey = innerNavigationExpansionExpression;
                }