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; }