private void InsertNavigationJoin(NavigationJoin navigationJoin) { var insertionIndex = 0; var bodyClause = navigationJoin.QuerySource as IBodyClause; if (bodyClause != null) { insertionIndex = _queryModel.BodyClauses.IndexOf(bodyClause) + 1; } if (_queryModel.MainFromClause == navigationJoin.QuerySource || insertionIndex > 0 || _parentvisitor == null) { foreach (var nj in navigationJoin.Iterate()) { _queryModel.BodyClauses.Insert(insertionIndex++, nj.JoinClause ?? (IBodyClause)nj.GroupJoinClause); foreach (var additionalBodyClause in nj.AdditionalBodyClauses) { _queryModel.BodyClauses.Insert(insertionIndex++, additionalBodyClause); } } } else { _parentvisitor.InsertNavigationJoin(navigationJoin); } }
public static void RemoveNavigationJoin( ICollection <NavigationJoin> navigationJoins, NavigationJoin navigationJoin) { if (!navigationJoins.Remove(navigationJoin)) { foreach (var nj in navigationJoins) { nj.Remove(navigationJoin); } } }
private Expression RewriteNavigationsIntoJoins( QuerySourceReferenceExpression outerQuerySourceReferenceExpression, IEnumerable <INavigation> navigations, PropertyInfo member) { var querySourceReferenceExpression = outerQuerySourceReferenceExpression; var navigationJoins = _navigationJoins; var optionalNavigationInChain = false; foreach (var navigation in navigations) { if (!navigation.ForeignKey.IsRequired) { optionalNavigationInChain = true; } var targetEntityType = navigation.GetTargetType(); if (navigation.IsCollection()) { _queryModel.MainFromClause.FromExpression = CreateEntityQueryable(targetEntityType); var innerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(_queryModel.MainFromClause); var leftKeyAccess = CreateKeyAccessExpression( querySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties : navigation.ForeignKey.PrincipalKey.Properties); var rightKeyAccess = CreateKeyAccessExpression( innerQuerySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.PrincipalKey.Properties : navigation.ForeignKey.Properties); _queryModel.BodyClauses.Add( new WhereClause( CreateKeyComparisonExpression(leftKeyAccess, rightKeyAccess))); return(_queryModel.MainFromClause.FromExpression); } var navigationJoin = navigationJoins .FirstOrDefault(nj => nj.QuerySource == querySourceReferenceExpression.ReferencedQuerySource && nj.Navigation == navigation); if (navigationJoin == null) { QuerySourceReferenceExpression innerQuerySourceReferenceExpression; var joinClause = BuildJoinFromNavigation( querySourceReferenceExpression, navigation, targetEntityType, optionalNavigationInChain, out innerQuerySourceReferenceExpression); var additionalBodyClauses = new List <IBodyClause>(); if (optionalNavigationInChain || !navigation.ForeignKey.IsRequired) { var groupJoinClause = new GroupJoinClause( joinClause.ItemName + "_group", typeof(IEnumerable <>).MakeGenericType(targetEntityType.ClrType), joinClause); var groupReferenceExpression = new QuerySourceReferenceExpression(groupJoinClause); var defaultIfEmptyMainFromClause = new MainFromClause(joinClause.ItemName + "_groupItem", joinClause.ItemType, groupReferenceExpression); var newQuerySourceReferenceExpression = new QuerySourceReferenceExpression(defaultIfEmptyMainFromClause); var defaultIfEmptyQueryModel = new QueryModel( defaultIfEmptyMainFromClause, new SelectClause(newQuerySourceReferenceExpression)); defaultIfEmptyQueryModel.ResultOperators.Add(new DefaultIfEmptyResultOperator(null)); var defaultIfEmptySubquery = new SubQueryExpression(defaultIfEmptyQueryModel); var defaultIfEmptyAdditionalFromClause = new AdditionalFromClause(joinClause.ItemName, joinClause.ItemType, defaultIfEmptySubquery); additionalBodyClauses.Add(defaultIfEmptyAdditionalFromClause); navigationJoins.Add( navigationJoin = new NavigationJoin( querySourceReferenceExpression.ReferencedQuerySource, navigation, groupJoinClause, additionalBodyClauses, optionalNavigationInChain, navigation.IsDependentToPrincipal(), new QuerySourceReferenceExpression(defaultIfEmptyAdditionalFromClause))); } else { navigationJoins.Add( navigationJoin = new NavigationJoin( querySourceReferenceExpression.ReferencedQuerySource, navigation, joinClause, additionalBodyClauses, optionalNavigationInChain, navigation.IsDependentToPrincipal(), innerQuerySourceReferenceExpression)); } } querySourceReferenceExpression = navigationJoin.QuerySourceReferenceExpression; navigationJoins = navigationJoin.NavigationJoins; } if (member == null) { return(querySourceReferenceExpression); } if (optionalNavigationInChain) { Expression memberAccessExpression = Expression.MakeMemberAccess(querySourceReferenceExpression, member); if (!member.PropertyType.IsNullableType()) { memberAccessExpression = Expression.Convert(memberAccessExpression, member.PropertyType.MakeNullable()); } var constantNullExpression = member.PropertyType.IsNullableType() ? Expression.Constant(null, member.PropertyType) : Expression.Constant(null, member.PropertyType.MakeNullable()); return(Expression.Condition( Expression.NotEqual( querySourceReferenceExpression, Expression.Constant(null, querySourceReferenceExpression.Type)), memberAccessExpression, constantNullExpression)); } return(Expression.MakeMemberAccess(querySourceReferenceExpression, member)); }
protected override Expression VisitBinary(BinaryExpression node) { var newLeft = Visit(node.Left); var newRight = Visit(node.Right); if (newLeft == node.Left && newRight == node.Right) { return(node); } var leftNavigationJoin = _navigationJoins .SelectMany(nj => nj.Iterate()) .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newLeft)); var rightNavigationJoin = _navigationJoins .SelectMany(nj => nj.Iterate()) .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newRight)); var leftJoin = leftNavigationJoin?.JoinClause ?? leftNavigationJoin?.GroupJoinClause?.JoinClause; var rightJoin = rightNavigationJoin?.JoinClause ?? rightNavigationJoin?.GroupJoinClause?.JoinClause; if (leftNavigationJoin != null && rightNavigationJoin != null) { if (leftNavigationJoin.DependentToPrincipal && rightNavigationJoin.DependentToPrincipal) { newLeft = leftJoin?.OuterKeySelector; newRight = rightJoin?.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, leftNavigationJoin); NavigationJoin.RemoveNavigationJoin(_navigationJoins, rightNavigationJoin); } } else { if (leftNavigationJoin != null) { var constantExpression = newRight as ConstantExpression; if (constantExpression != null && constantExpression.Value == null) { if (leftNavigationJoin.DependentToPrincipal) { newLeft = leftJoin?.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, leftNavigationJoin); if (newLeft != null && IsCompositeKey(newLeft.Type)) { newRight = CreateNullCompositeKey(newLeft); } } } else { newLeft = leftJoin?.InnerKeySelector; } } if (rightNavigationJoin != null) { var constantExpression = newLeft as ConstantExpression; if (constantExpression != null && constantExpression.Value == null) { if (rightNavigationJoin.DependentToPrincipal) { newRight = rightJoin?.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, rightNavigationJoin); if (newRight != null && IsCompositeKey(newRight.Type)) { newLeft = CreateNullCompositeKey(newRight); } } } else { newRight = rightJoin?.InnerKeySelector; } } } if (node.NodeType != ExpressionType.ArrayIndex && newLeft != null && newRight != null && newLeft.Type != newRight.Type) { if (newLeft.Type.IsNullableType() && !newRight.Type.IsNullableType()) { newRight = Expression.Convert(newRight, newLeft.Type); } else if (!newLeft.Type.IsNullableType() && newRight.Type.IsNullableType()) { newLeft = Expression.Convert(newLeft, newRight.Type); } } return(Expression.MakeBinary(node.NodeType, newLeft, newRight)); }
private void Remove(NavigationJoin navigationJoin) => RemoveNavigationJoin(NavigationJoins, navigationJoin);
private Expression CreateJoinsForNavigations( QuerySourceReferenceExpression outerQuerySourceReferenceExpression, IEnumerable <INavigation> navigations) { var querySourceReferenceExpression = outerQuerySourceReferenceExpression; var navigationJoins = _navigationJoins; foreach (var navigation in navigations) { var targetEntityType = navigation.GetTargetType(); if (navigation.IsCollection()) { _queryModel.MainFromClause.FromExpression = CreateEntityQueryable(targetEntityType); var innerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(_queryModel.MainFromClause); var leftKeyAccess = CreateKeyAccessExpression( querySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties : navigation.ForeignKey.PrincipalKey.Properties); var rightKeyAccess = CreateKeyAccessExpression( innerQuerySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.PrincipalKey.Properties : navigation.ForeignKey.Properties); _queryModel.BodyClauses.Add( new WhereClause( CreateKeyComparisonExpression(leftKeyAccess, rightKeyAccess))); return(_queryModel.MainFromClause.FromExpression); } var navigationJoin = navigationJoins .FirstOrDefault(nj => nj.QuerySource == querySourceReferenceExpression.ReferencedQuerySource && nj.Navigation == navigation); if (navigationJoin == null) { var joinClause = new JoinClause( $"{querySourceReferenceExpression.ReferencedQuerySource.ItemName}.{navigation.Name}", targetEntityType.ClrType, CreateEntityQueryable(targetEntityType), CreateKeyAccessExpression( querySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.Properties : navigation.ForeignKey.PrincipalKey.Properties), Expression.Constant(null)); var innerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(joinClause); var innerKeySelector = CreateKeyAccessExpression( innerQuerySourceReferenceExpression, navigation.IsDependentToPrincipal() ? navigation.ForeignKey.PrincipalKey.Properties : navigation.ForeignKey.Properties); if (innerKeySelector.Type != joinClause.OuterKeySelector.Type) { innerKeySelector = Expression.Convert( innerKeySelector, joinClause.OuterKeySelector.Type); } joinClause.InnerKeySelector = innerKeySelector; navigationJoins.Add( navigationJoin = new NavigationJoin( querySourceReferenceExpression.ReferencedQuerySource, navigation, joinClause, innerQuerySourceReferenceExpression)); } querySourceReferenceExpression = navigationJoin.QuerySourceReferenceExpression; navigationJoins = navigationJoin.NavigationJoins; } return(querySourceReferenceExpression); }
protected override Expression VisitBinary(BinaryExpression binaryExpression) { var newLeft = Visit(binaryExpression.Left); var newRight = Visit(binaryExpression.Right); var leftNavigationJoin = _navigationJoins .SelectMany(nj => nj.Iterate()) .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newLeft)); var rightNavigationJoin = _navigationJoins .SelectMany(nj => nj.Iterate()) .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newRight)); if (leftNavigationJoin != null && rightNavigationJoin != null) { newLeft = leftNavigationJoin.JoinClause.OuterKeySelector; newRight = rightNavigationJoin.JoinClause.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, leftNavigationJoin); NavigationJoin.RemoveNavigationJoin(_navigationJoins, rightNavigationJoin); } else { if (leftNavigationJoin != null) { var constantExpression = newRight as ConstantExpression; if (constantExpression != null && constantExpression.Value == null) { newLeft = leftNavigationJoin.JoinClause.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, leftNavigationJoin); if (IsCompositeKey(newLeft.Type)) { newRight = CreateNullCompositeKey(newLeft); } } else { newLeft = leftNavigationJoin.JoinClause.InnerKeySelector; } } if (rightNavigationJoin != null) { var constantExpression = newLeft as ConstantExpression; if (constantExpression != null && constantExpression.Value == null) { newRight = rightNavigationJoin.JoinClause.OuterKeySelector; NavigationJoin.RemoveNavigationJoin(_navigationJoins, rightNavigationJoin); if (IsCompositeKey(newRight.Type)) { newLeft = CreateNullCompositeKey(newRight); } } else { newRight = rightNavigationJoin.JoinClause.InnerKeySelector; } } } return(Expression.MakeBinary( binaryExpression.NodeType, newLeft, newRight, binaryExpression.IsLiftedToNull, binaryExpression.Method)); }
private Expression CreateJoinsForNavigations( QuerySourceReferenceExpression outerQuerySourceReferenceExpression, IEnumerable <INavigation> navigations) { var querySourceReferenceExpression = outerQuerySourceReferenceExpression; var navigationJoins = _navigationJoins; foreach (var navigation in navigations) { var navigationJoin = navigationJoins .FirstOrDefault(nj => nj.QuerySource == querySourceReferenceExpression.ReferencedQuerySource && nj.Navigation == navigation); if (navigationJoin == null) { var targetEntityType = navigation.GetTargetType(); var joinClause = new JoinClause( $"{querySourceReferenceExpression.ReferencedQuerySource.ItemName}.{navigation.Name}", targetEntityType.ClrType, Expression.Constant( _createEntityQueryableMethod .MakeGenericMethod(targetEntityType.ClrType) .Invoke(null, new object[] { _entityQueryProvider })), CreatePropertyCallExpression( querySourceReferenceExpression, navigation.ForeignKey.Properties.Single()), Expression.Constant(null)); var innerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(joinClause); Expression innerKeySelector = CreatePropertyCallExpression( innerQuerySourceReferenceExpression, targetEntityType.GetPrimaryKey().Properties.Single()); if (innerKeySelector.Type != joinClause.OuterKeySelector.Type) { innerKeySelector = Expression.Convert( innerKeySelector, joinClause.OuterKeySelector.Type); } joinClause.InnerKeySelector = innerKeySelector; navigationJoins.Add( navigationJoin = new NavigationJoin( querySourceReferenceExpression.ReferencedQuerySource, navigation, joinClause, innerQuerySourceReferenceExpression)); } querySourceReferenceExpression = navigationJoin.QuerySourceReferenceExpression; navigationJoins = navigationJoin.NavigationJoins; } return(querySourceReferenceExpression); }