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.CustomRootMappings, navigationExpansionExpression.State.MaterializeCollectionNavigation); var navigationExpression = new NavigationExpansionExpression( navigationExpansionExpression.Operand, newNavigationExpansionExpressionState, navigationKeyAccessExpression.Type); return(navigationExpression, nullKeyExpression); }
private NavigationBindingExpression CreateParentBindingExpression(NavigationBindingExpression navigationBindingExpression) { // TODO: verify this is correct in all cases var parentNavigationEntityType = navigationBindingExpression.NavigationTreeNode.Navigation.FindInverse().GetTargetType(); var parentTreeNode = navigationBindingExpression.NavigationTreeNode.Parent; parentTreeNode.Children.Remove(navigationBindingExpression.NavigationTreeNode); return(new NavigationBindingExpression( navigationBindingExpression.RootParameter, parentTreeNode, parentNavigationEntityType, navigationBindingExpression.SourceMapping, parentNavigationEntityType.ClrType)); }
public static Expression CreateCollectionNavigationExpression( NavigationTreeNode navigationTreeNode, ParameterExpression rootParameter, SourceMapping sourceMapping) { var collectionEntityType = navigationTreeNode.Navigation.ForeignKey.DeclaringEntityType; Expression operand; if (navigationTreeNode.IncludeState == NavigationState.Pending || navigationTreeNode.ExpansionState == NavigationState.Pending) { var entityQueryable = (Expression)NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(collectionEntityType.ClrType); var outerBinding = new NavigationBindingExpression( rootParameter, navigationTreeNode.Parent, navigationTreeNode.Navigation.DeclaringEntityType, sourceMapping, navigationTreeNode.Navigation.DeclaringEntityType.ClrType); var outerKeyAccess = NavigationExpansionHelpers.CreateKeyAccessExpression( outerBinding, navigationTreeNode.Navigation.ForeignKey.PrincipalKey.Properties, addNullCheck: outerBinding.NavigationTreeNode.Optional); var collectionCurrentParameter = Expression.Parameter( collectionEntityType.ClrType, collectionEntityType.ClrType.GenerateParameterName()); var innerKeyAccess = NavigationExpansionHelpers.CreateKeyAccessExpression( collectionCurrentParameter, navigationTreeNode.Navigation.ForeignKey.Properties); var predicate = Expression.Lambda( CreateKeyComparisonExpressionForCollectionNavigationSubquery( outerKeyAccess, innerKeyAccess, outerBinding), collectionCurrentParameter); operand = Expression.Call( LinqMethodHelpers.QueryableWhereMethodInfo.MakeGenericMethod(collectionEntityType.ClrType), entityQueryable, predicate); } else { operand = new NavigationBindingExpression( rootParameter, navigationTreeNode, collectionEntityType, sourceMapping, collectionEntityType.ClrType); } var result = NavigationExpansionHelpers.CreateNavigationExpansionRoot( operand, collectionEntityType, navigationTreeNode.Navigation); // this is needed for cases like: root.Include(r => r.Collection).ThenInclude(c => c.Reference).Select(r => r.Collection) // result should be elements of the collection navigation with their 'Reference' included var newSourceMapping = result.State.SourceMappings.Single(); IncludeHelpers.CopyIncludeInformation(navigationTreeNode, newSourceMapping.NavigationTree, newSourceMapping); return(result); }