private (NavigationExpansionExpression navigationExpression, Expression nullKeyExpression) CreateNullComparisonArguments( NavigationBindingExpression navigationBindingExpression, NavigationExpansionExpression navigationExpansionExpression) { var navigationKeyAccessExpression = NavigationExpansionHelpers.CreateKeyAccessExpression( navigationBindingExpression, new[] { navigationBindingExpression.EntityType.FindPrimaryKey().Properties.First() }, addNullCheck: true); var nullKeyExpression = NavigationExpansionHelpers.CreateNullKeyExpression( navigationKeyAccessExpression.Type, keyCount: 1); var newNavigationExpansionExpressionState = new NavigationExpansionExpressionState( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings, Expression.Lambda(navigationKeyAccessExpression, navigationExpansionExpression.State.PendingSelector.Parameters[0]), applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, // we need to remap cardinality reducing operator since it's source type has now changed navigationExpansionExpression.State.PendingCardinalityReducingOperator?.GetGenericMethodDefinition().MakeGenericMethod(navigationKeyAccessExpression.Type), navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); var navigationExpression = new NavigationExpansionExpression( navigationExpansionExpression.Operand, newNavigationExpansionExpressionState, navigationKeyAccessExpression.Type); return(navigationExpression, nullKeyExpression); }
private (NavigationExpansionExpression navigationExpression, Expression nullKeyExpression) CreateNullComparisonArguments( NavigationBindingExpression navigationBindingExpression, NavigationExpansionExpression navigationExpansionExpression) { var navigationKeyAccessExpression = NavigationExpansionHelpers.CreateKeyAccessExpression( navigationBindingExpression, navigationBindingExpression.EntityType.FindPrimaryKey().Properties, addNullCheck: true); var nullKeyExpression = NavigationExpansionHelpers.CreateNullKeyExpression( navigationKeyAccessExpression.Type, navigationBindingExpression.EntityType.FindPrimaryKey().Properties.Count); var newNavigationExpansionExpressionState = new NavigationExpansionExpressionState( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings, Expression.Lambda(navigationKeyAccessExpression, navigationExpansionExpression.State.PendingSelector.Parameters[0]), applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, navigationExpansionExpression.State.PendingCardinalityReducingOperator, navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); var navigationExpression = new NavigationExpansionExpression( navigationExpansionExpression.Operand, newNavigationExpansionExpressionState, navigationKeyAccessExpression.Type); return(navigationExpression, nullKeyExpression); }
private Expression RemoveMaterializeCollection(Expression expression) { if (expression is NavigationExpansionExpression navigationExpansionExpression && navigationExpansionExpression.State.MaterializeCollectionNavigation != null) { navigationExpansionExpression.State.MaterializeCollectionNavigation = null; return(new NavigationExpansionExpression( navigationExpansionExpression.Operand, navigationExpansionExpression.State, navigationExpansionExpression.Operand.Type)); } if (expression is NavigationExpansionRootExpression navigationExpansionRootExpression && navigationExpansionRootExpression.NavigationExpansion.State.MaterializeCollectionNavigation != null) { navigationExpansionRootExpression.NavigationExpansion.State.MaterializeCollectionNavigation = null; var rewritten = new NavigationExpansionExpression( navigationExpansionRootExpression.NavigationExpansion.Operand, navigationExpansionRootExpression.NavigationExpansion.State, navigationExpansionRootExpression.NavigationExpansion.Operand.Type); return(new NavigationExpansionRootExpression(rewritten, navigationExpansionRootExpression.Mapping)); } return(expression); }
private (Expression Operand, NavigationExpansionExpressionState State) ApplyIncludes( NavigationExpansionExpression navigationExpansionExpression) { var includeVisitor = new PendingSelectorIncludeVisitor(); var rewrittenBody = includeVisitor.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 (includeVisitor.PendingIncludes.Count > 0) { var result = (Source : navigationExpansionExpression.Operand, Parameter : navigationExpansionExpression.State.CurrentParameter); foreach (var pendingIncludeNode in includeVisitor.PendingIncludes) { result = NavigationExpansionHelpers.AddNavigationJoin( result.Source, result.Parameter, pendingIncludeNode.SourceMapping, pendingIncludeNode.NavTreeNode, 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.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); return(Operand : result.Source, newState); } return(navigationExpansionExpression.Operand, navigationExpansionExpression.State); }
public GroupByNavigationExpansionExpression( Expression source, ParameterExpression groupingParameter, NavigationTreeNode currentTree, Expression pendingSelector, string innerParameterName) { Source = source; CurrentParameter = groupingParameter; Type = source.Type; GroupingEnumerable = new NavigationExpansionExpression( Call(QueryableMethods.AsQueryable.MakeGenericMethod(CurrentParameter.Type.GetGenericArguments()[1]), CurrentParameter), currentTree, pendingSelector, innerParameterName); }
private Expression ProcessMemberPushdown( Expression source, NavigationExpansionExpression navigationExpansionExpression, bool efProperty, MemberInfo memberInfo, string propertyName, Type resultType) { // in case of nested FirstOrDefaults, we need to dig into the inner most - that's where the member finally gets pushed down to if (navigationExpansionExpression.State.PendingSelector.Body is NavigationExpansionExpression navigationExpansionPendingSelector && navigationExpansionPendingSelector.State.PendingCardinalityReducingOperator != null) { var newPendingSelector = (NavigationExpansionExpression)ProcessMemberPushdown(source, navigationExpansionPendingSelector, efProperty, memberInfo, propertyName, resultType); var newStateNested = new NavigationExpansionExpressionState( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings, Expression.Lambda(newPendingSelector, navigationExpansionExpression.State.CurrentParameter), applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, // we need to remap cardinality reducing operator since it's source type has now changed navigationExpansionExpression.State.PendingCardinalityReducingOperator.GetGenericMethodDefinition().MakeGenericMethod(newPendingSelector.Type), navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); return(new NavigationExpansionExpression( navigationExpansionExpression.Operand, newStateNested, resultType)); } var selectorParameter = Expression.Parameter(source.Type, navigationExpansionExpression.State.CurrentParameter.Name); var selectorBody = efProperty ? (Expression)Expression.Call(EF.PropertyMethod.MakeGenericMethod(resultType), selectorParameter, Expression.Constant(propertyName)) : Expression.MakeMemberAccess(selectorParameter, memberInfo); if (navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.QueryableFirstOrDefaultMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.QueryableFirstOrDefaultPredicateMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.QueryableSingleOrDefaultMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.QueryableSingleOrDefaultPredicateMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.EnumerableFirstOrDefaultMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.EnumerableFirstOrDefaultPredicateMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.EnumerableSingleOrDefaultMethodInfo) || navigationExpansionExpression.State.PendingCardinalityReducingOperator.MethodIsClosedFormOf(LinqMethodHelpers.EnumerableSingleOrDefaultPredicateMethodInfo)) { if (!selectorBody.Type.IsNullableType()) { selectorBody = Expression.Convert(selectorBody, selectorBody.Type.MakeNullable()); } } var selector = Expression.Lambda(selectorBody, selectorParameter); var remappedSelectorBody = ExpressionExtensions.CombineAndRemap(selector.Body, selectorParameter, navigationExpansionExpression.State.PendingSelector.Body); var binder = new NavigationPropertyBindingVisitor( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings); var boundSelectorBody = binder.Visit(remappedSelectorBody); if (boundSelectorBody is NavigationBindingExpression navigationBindingExpression && navigationBindingExpression.NavigationTreeNode.Navigation is INavigation lastNavigation && lastNavigation != null) { if (lastNavigation.IsCollection()) { var collectionNavigationElementType = lastNavigation.ForeignKey.DeclaringEntityType.ClrType; var entityQueryable = NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(collectionNavigationElementType); var outerParameter = Expression.Parameter(collectionNavigationElementType, collectionNavigationElementType.GenerateParameterName()); var outerKeyAccess = NavigationExpansionHelpers.CreateKeyAccessExpression( outerParameter, lastNavigation.ForeignKey.Properties); var innerParameter = Expression.Parameter(navigationExpansionExpression.Type); var innerKeyAccessLambda = Expression.Lambda( NavigationExpansionHelpers.CreateKeyAccessExpression( innerParameter, lastNavigation.ForeignKey.PrincipalKey.Properties), innerParameter); var combinedKeySelectorBody = ExpressionExtensions.CombineAndRemap(innerKeyAccessLambda.Body, innerKeyAccessLambda.Parameters[0], navigationExpansionExpression.State.PendingSelector.Body); if (outerKeyAccess.Type != combinedKeySelectorBody.Type) { if (combinedKeySelectorBody.Type.IsNullableType()) { outerKeyAccess = Expression.Convert(outerKeyAccess, combinedKeySelectorBody.Type); } else { combinedKeySelectorBody = Expression.Convert(combinedKeySelectorBody, outerKeyAccess.Type); } } var rewrittenState = new NavigationExpansionExpressionState( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings, Expression.Lambda(combinedKeySelectorBody, navigationExpansionExpression.State.CurrentParameter), applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, // we need to remap cardinality reducing operator since it's source type has now changed navigationExpansionExpression.State.PendingCardinalityReducingOperator.GetGenericMethodDefinition().MakeGenericMethod(combinedKeySelectorBody.Type), navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, materializeCollectionNavigation: null); var rewrittenNavigationExpansionExpression = new NavigationExpansionExpression(navigationExpansionExpression.Operand, rewrittenState, combinedKeySelectorBody.Type); var inner = new NavigationExpansionReducingVisitor().Visit(rewrittenNavigationExpansionExpression); var predicate = Expression.Lambda( Expression.Equal(outerKeyAccess, inner), outerParameter); var whereMethodInfo = LinqMethodHelpers.QueryableWhereMethodInfo.MakeGenericMethod(collectionNavigationElementType); var rewritten = Expression.Call( whereMethodInfo, entityQueryable, predicate); var entityType = lastNavigation.ForeignKey.DeclaringEntityType; return(NavigationExpansionHelpers.CreateNavigationExpansionRoot(rewritten, entityType, materializeCollectionNavigation: null)); } else { return(ProcessSelectCore( navigationExpansionExpression.Operand, navigationExpansionExpression.State, selector, selectorBody.Type)); } } var newState = new NavigationExpansionExpressionState( navigationExpansionExpression.State.CurrentParameter, navigationExpansionExpression.State.SourceMappings, Expression.Lambda(boundSelectorBody, navigationExpansionExpression.State.CurrentParameter), applyPendingSelector: true, navigationExpansionExpression.State.PendingOrderings, navigationExpansionExpression.State.PendingIncludeChain, // we need to remap cardinality reducing operator since it's source type has now changed navigationExpansionExpression.State.PendingCardinalityReducingOperator.GetGenericMethodDefinition().MakeGenericMethod(boundSelectorBody.Type), navigationExpansionExpression.State.PendingTags, navigationExpansionExpression.State.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); // TODO: expand navigations var result = new NavigationExpansionExpression( navigationExpansionExpression.Operand, newState, selectorBody.Type); return(resultType != result.Type ? (Expression)Expression.Convert(result, resultType) : result); }