예제 #1
0
        public override Expression Visit(Expression node)
        {
            var visited = base.Visit(node);

            switch (visited)
            {
            case GroupByResultExpression groupByResultExpression:
            {
                var uniquifier = new TableUniquifyingExpressionVisitor();

                var oldSelectExpression = groupByResultExpression.SelectExpression;
                var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(VisitMethodCall));

                var oldTables = oldSelectExpression.Table.Flatten().ToArray();
                var newTables = newSelectExpression.Table.Flatten().ToArray();

                var updater = new TableUpdatingExpressionVisitor(oldTables, newTables);

                var outerKeySelector = groupByResultExpression.OuterKeySelector;
                var innerKeySelector = updater.Visit(groupByResultExpression.InnerKeySelector);
                var elementSelector  = updater.Visit(groupByResultExpression.ElementSelector);

                var elements
                    = new EnumerableRelationalQueryExpression(
                          newSelectExpression
                          .UpdateProjection(new ServerProjectionExpression(elementSelector))
                          .AddToPredicate(Expression.Equal(outerKeySelector, innerKeySelector)));

                return(ExpandGroup(visited, outerKeySelector, elements));
            }

            case GroupedRelationalQueryExpression groupedRelationalQueryExpression:
            {
                var outerKeySelector = groupedRelationalQueryExpression.OuterKeySelector;
                var innerKeySelector = groupedRelationalQueryExpression.InnerKeySelector;

                if (groupedRelationalQueryExpression.RequiresDenullification)
                {
                    outerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(outerKeySelector);
                    innerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(innerKeySelector);
                }

                var elements
                    = new EnumerableRelationalQueryExpression(
                          groupedRelationalQueryExpression.SelectExpression
                          .AddToPredicate(
                              Expression.Equal(
                                  outerKeySelector,
                                  innerKeySelector)));

                return(ExpandGroup(visited, groupedRelationalQueryExpression.OuterKeySelector, elements));
            }

            default:
            {
                return(visited);
            }
            }
        }
        public override Expression Visit(Expression node)
        {
            IEnumerable <string> GetNameParts()
            {
                return(currentPath.Reverse().Where(n => n != null && !n.StartsWith("<>")));
            }

            switch (node)
            {
            case null:
            {
                return(null);
            }

            case NewExpression newExpression:
            {
                if (newExpression.Members == null)
                {
                    return(newExpression);
                }

                var arguments = newExpression.Arguments.ToArray();

                for (var i = 0; i < newExpression.Members.Count; i++)
                {
                    currentPath.Push(newExpression.Members[i].GetPathSegmentName());
                    arguments[i] = Visit(arguments[i]);
                    currentPath.Pop();
                }

                return(newExpression.Update(arguments));
            }

            case MemberInitExpression memberInitExpression:
            {
                var newExpression = (NewExpression)Visit(memberInitExpression.NewExpression);
                var bindings      = memberInitExpression.Bindings.ToArray();

                for (var i = 0; i < bindings.Length; i++)
                {
                    currentPath.Push(bindings[i].Member.GetPathSegmentName());
                    bindings[i] = VisitMemberBinding(bindings[i]);
                    currentPath.Pop();
                }

                return(memberInitExpression.Update(newExpression, bindings));
            }

            case GroupByResultExpression groupByResultExpression:
            {
                var uniquifier = new TableUniquifyingExpressionVisitor();

                var oldSelectExpression = groupByResultExpression.SelectExpression;
                var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(Visit));

                var oldTables = oldSelectExpression.Table.Flatten().ToArray();
                var newTables = newSelectExpression.Table.Flatten().ToArray();

                var updater = new TableUpdatingExpressionVisitor(oldTables, newTables);

                currentPath.Push("Key");

                var outerKeySelector = Visit(groupByResultExpression.OuterKeySelector);
                var innerKeySelector = updater.Visit(groupByResultExpression.InnerKeySelector);
                var elementSelector  = updater.Visit(groupByResultExpression.ElementSelector);

                currentPath.Pop();

                return(new GroupedRelationalQueryExpression(
                           newSelectExpression.UpdateProjection(new ServerProjectionExpression(elementSelector)),
                           outerKeySelector,
                           innerKeySelector,
                           groupByResultExpression.InnerKeyLambda,
                           requiresDenullification: false,
                           type: groupByResultExpression.Type));
            }

            case GroupedRelationalQueryExpression groupedRelationalQueryExpression:
            {
                var uniquifier = new TableUniquifyingExpressionVisitor();

                var oldSelectExpression = groupedRelationalQueryExpression.SelectExpression;
                var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(Visit));

                var oldTables = oldSelectExpression.Table.Flatten().ToArray();
                var newTables = newSelectExpression.Table.Flatten().ToArray();

                var updater = new TableUpdatingExpressionVisitor(oldTables, newTables);

                currentPath.Push("Key");

                var outerKeySelector = Visit(groupedRelationalQueryExpression.OuterKeySelector);
                var innerKeySelector = updater.Visit(groupedRelationalQueryExpression.InnerKeySelector);

                currentPath.Pop();

                return(new GroupedRelationalQueryExpression(
                           newSelectExpression,
                           outerKeySelector,
                           innerKeySelector,
                           groupedRelationalQueryExpression.InnerKeyLambda,
                           groupedRelationalQueryExpression.RequiresDenullification,
                           groupedRelationalQueryExpression.Type));
            }

            case DefaultIfEmptyExpression defaultIfEmptyExpression:
            {
                var expression = sqlColumnNullabilityExpressionVisitor.Visit(Visit(defaultIfEmptyExpression.Expression));

                var parts = GetNameParts().Append("$empty");

                var name = string.Join(".", parts);

                var flag = new SqlColumnExpression(targetTable, name, typeof(bool?), true);

                return(new DefaultIfEmptyExpression(expression, flag));
            }

            case PolymorphicExpression polymorphicExpression:
            {
                return(new PolymorphicExpression(
                           polymorphicExpression.Type,
                           Visit(polymorphicExpression.Row),
                           polymorphicExpression.Descriptors));
            }

            case AnnotationExpression annotationExpression:
            {
                return(VisitExtension(annotationExpression));
            }

            default:
            {
                var parts      = GetNameParts();
                var isNullable = !node.Type.GetTypeInfo().IsValueType;

                switch (node)
                {
                case SqlColumnExpression sqlColumnExpression:
                {
                    parts      = parts.DefaultIfEmpty(sqlColumnExpression.ColumnName);
                    isNullable = sqlColumnExpression.IsNullable;
                    break;
                }

                case SqlAliasExpression sqlAliasExpression:
                {
                    parts = parts.DefaultIfEmpty(sqlAliasExpression.Alias);
                    break;
                }
                }

                return(new SqlColumnExpression(
                           targetTable,
                           string.Join(".", parts),
                           node.Type,
                           isNullable));
            }
            }
        }