private (Expression operand, NavigationExpansionExpressionState state) ApplyIncludes(NavigationExpansionExpression navigationExpansionExpression) { var includeFinder = new PendingIncludeFindingVisitor(); includeFinder.Visit(navigationExpansionExpression.State.PendingSelector.Body); var includeRewriter = new PendingSelectorIncludeRewriter(); var rewrittenBody = includeRewriter.Visit(navigationExpansionExpression.State.PendingSelector.Body); if (navigationExpansionExpression.State.PendingSelector.Body != rewrittenBody) { navigationExpansionExpression.State.PendingSelector = Expression.Lambda(rewrittenBody, navigationExpansionExpression.State.PendingSelector.Parameters[0]); navigationExpansionExpression.State.ApplyPendingSelector = true; } if (includeFinder.PendingIncludes.Count > 0) { var result = (source : navigationExpansionExpression.Operand, parameter : navigationExpansionExpression.State.CurrentParameter); foreach (var pendingIncludeNode in includeFinder.PendingIncludes) { result = NavigationExpansionHelpers.AddNavigationJoin( result.source, result.parameter, pendingIncludeNode.Value, pendingIncludeNode.Key, navigationExpansionExpression.State, new List <INavigation>(), include: true); } var pendingSelector = navigationExpansionExpression.State.PendingSelector; if (navigationExpansionExpression.State.CurrentParameter != result.parameter) { var pendingSelectorBody = new ExpressionReplacingVisitor(navigationExpansionExpression.State.CurrentParameter, result.parameter).Visit(navigationExpansionExpression.State.PendingSelector.Body); pendingSelector = Expression.Lambda(pendingSelectorBody, result.parameter); } var newState = new NavigationExpansionExpressionState( result.parameter, navigationExpansionExpression.State.SourceMappings, pendingSelector, applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, navigationExpansionExpression.State.PendingCardinalityReducingOperator, navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); return(operand : result.source, state : newState); } return(operand : navigationExpansionExpression.Operand, state : navigationExpansionExpression.State); }
protected override Expression VisitExtension(Expression extensionExpression) { if (extensionExpression is NavigationBindingExpression navigationBindingExpression) { var result = navigationBindingExpression.RootParameter.BuildPropertyAccess(navigationBindingExpression.NavigationTreeNode.ToMapping); return(result); } if (extensionExpression is NavigationExpansionRootExpression navigationExpansionRootExpression) { return(Visit(navigationExpansionRootExpression.Unwrap())); } if (extensionExpression is NavigationExpansionExpression navigationExpansionExpression) { var includeResult = ApplyIncludes(navigationExpansionExpression); var state = includeResult.state; var result = Visit(includeResult.operand); if (!state.ApplyPendingSelector && state.PendingOrderings.Count == 0 && state.PendingTags.Count == 0 && state.PendingCardinalityReducingOperator == null && state.MaterializeCollectionNavigation == null) { return(result); } var parameter = Expression.Parameter(result.Type.GetSequenceType()); foreach (var pendingOrdering in state.PendingOrderings) { var remappedKeySelectorBody = new ExpressionReplacingVisitor(pendingOrdering.keySelector.Parameters[0], state.CurrentParameter).Visit(pendingOrdering.keySelector.Body); var newSelectorBody = new NavigationPropertyUnbindingVisitor(state.CurrentParameter).Visit(remappedKeySelectorBody); var newSelector = Expression.Lambda(newSelectorBody, state.CurrentParameter); var orderingMethod = pendingOrdering.method.MakeGenericMethod(state.CurrentParameter.Type, newSelectorBody.Type); result = Expression.Call(orderingMethod, result, newSelector); } if (state.ApplyPendingSelector) { var pendingSelector = (LambdaExpression) new NavigationPropertyUnbindingVisitor(state.CurrentParameter).Visit(state.PendingSelector); var pendingSelectorBodyType = pendingSelector.Type.GetGenericArguments()[1]; var pendingSelectMathod = result.Type.IsGenericType && (result.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>) || result.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>)) ? LinqMethodHelpers.EnumerableSelectMethodInfo.MakeGenericMethod(parameter.Type, pendingSelectorBodyType) : LinqMethodHelpers.QueryableSelectMethodInfo.MakeGenericMethod(parameter.Type, pendingSelectorBodyType); result = Expression.Call(pendingSelectMathod, result, pendingSelector); parameter = Expression.Parameter(result.Type.GetSequenceType()); } if (state.PendingTags.Count > 0) { var withTagMethodInfo = EntityFrameworkQueryableExtensions.TagWithMethodInfo.MakeGenericMethod(parameter.Type); foreach (var pendingTag in state.PendingTags) { result = Expression.Call(withTagMethodInfo, result, Expression.Constant(pendingTag)); } } if (state.PendingCardinalityReducingOperator != null) { var terminatingOperatorMethodInfo = state.PendingCardinalityReducingOperator.MakeGenericMethod(parameter.Type); result = Expression.Call(terminatingOperatorMethodInfo, result); } if (state.MaterializeCollectionNavigation != null) { var entityType = state.MaterializeCollectionNavigation.ClrType.IsGenericType ? state.MaterializeCollectionNavigation.ClrType.GetGenericArguments()[0] : state.MaterializeCollectionNavigation.GetTargetType().ClrType; result = Expression.Call( NavigationExpansionHelpers.MaterializeCollectionNavigationMethodInfo.MakeGenericMethod( state.MaterializeCollectionNavigation.ClrType, entityType), result, Expression.Constant(state.MaterializeCollectionNavigation)); } if (navigationExpansionExpression.Type != result.Type && navigationExpansionExpression.Type.IsGenericType) { if (navigationExpansionExpression.Type.GetGenericTypeDefinition() == typeof(IOrderedQueryable <>)) { var toOrderedQueryableMethodInfo = ToOrderedQueryableMethod.MakeGenericMethod(parameter.Type); return(Expression.Call(toOrderedQueryableMethodInfo, result)); } else if (navigationExpansionExpression.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>)) { var toOrderedEnumerableMethodInfo = ToOrderedEnumerableMethod.MakeGenericMethod(parameter.Type); return(Expression.Call(toOrderedEnumerableMethodInfo, result)); } } return(result); } return(base.VisitExtension(extensionExpression)); }
protected override Expression VisitExtension(Expression extensionExpression) { switch (extensionExpression) { case NavigationBindingExpression navigationBindingExpression: return(navigationBindingExpression.RootParameter.BuildPropertyAccess( navigationBindingExpression.NavigationTreeNode.ToMapping)); case NavigationExpansionRootExpression navigationExpansionRootExpression: return(Visit(navigationExpansionRootExpression.Unwrap())); case NavigationExpansionExpression navigationExpansionExpression: { var(result, state) = ApplyIncludes(navigationExpansionExpression); result = Visit(result); if (!state.ApplyPendingSelector && state.PendingOrderings.Count == 0 && state.PendingCardinalityReducingOperator == null && state.MaterializeCollectionNavigation == null) { return(result); } var parameterType = result.Type.GetSequenceType(); foreach (var pendingOrdering in state.PendingOrderings) { var remappedKeySelectorBody = new ExpressionReplacingVisitor(pendingOrdering.keySelector.Parameters[0], state.CurrentParameter).Visit(pendingOrdering.keySelector.Body); var newSelectorBody = new NavigationPropertyUnbindingVisitor(state.CurrentParameter).Visit(remappedKeySelectorBody); var newSelector = Expression.Lambda(newSelectorBody, state.CurrentParameter); var orderingMethod = pendingOrdering.method.MakeGenericMethod(state.CurrentParameter.Type, newSelectorBody.Type); result = Expression.Call(orderingMethod, result, newSelector); } if (state.ApplyPendingSelector) { var pendingSelector = (LambdaExpression) new NavigationPropertyUnbindingVisitor(state.CurrentParameter).Visit(state.PendingSelector); var pendingSelectorBodyType = pendingSelector.Type.GetGenericArguments()[1]; var pendingSelectMethod = result.Type.IsGenericType && (result.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>) || result.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>)) ? LinqMethodHelpers.EnumerableSelectMethodInfo.MakeGenericMethod(parameterType, pendingSelectorBodyType) : LinqMethodHelpers.QueryableSelectMethodInfo.MakeGenericMethod(parameterType, pendingSelectorBodyType); result = Expression.Call(pendingSelectMethod, result, pendingSelector); parameterType = result.Type.GetSequenceType(); } if (state.PendingCardinalityReducingOperator != null) { result = Expression.Call(state.PendingCardinalityReducingOperator, result); } if (state.MaterializeCollectionNavigation != null) { result = new MaterializeCollectionNavigationExpression(result, state.MaterializeCollectionNavigation); } if (navigationExpansionExpression.Type != result.Type && navigationExpansionExpression.Type.IsGenericType) { if (navigationExpansionExpression.Type.GetGenericTypeDefinition() == typeof(IOrderedQueryable <>)) { var toOrderedQueryableMethodInfo = ToOrderedQueryableMethod.MakeGenericMethod(parameterType); return(Expression.Call(toOrderedQueryableMethodInfo, result)); } if (navigationExpansionExpression.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>)) { var toOrderedEnumerableMethodInfo = ToOrderedEnumerableMethod.MakeGenericMethod(parameterType); return(Expression.Call(toOrderedEnumerableMethodInfo, result)); } } return(result); } } return(base.VisitExtension(extensionExpression)); }