Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
 public static void RemoveNavigationJoin(
     ICollection <NavigationJoin> navigationJoins, NavigationJoin navigationJoin)
 {
     if (!navigationJoins.Remove(navigationJoin))
     {
         foreach (var nj in navigationJoins)
         {
             nj.Remove(navigationJoin);
         }
     }
 }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        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));
        }
Esempio n. 5
0
 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);
        }