Beispiel #1
0
        /// <summary>
        /// 解决 对象 到 类似 ICollection&lt;KeyValuePair&lt;TKey,TValue&gt;&gt; 类型的转换。
        /// </summary>
        /// <typeparam name="TResult">目标类型。</typeparam>
        /// <param name="sourceType">源类型。</param>
        /// <param name="conversionType">目标类型。</param>
        /// <param name="typeArgument">泛型【KeyValuePair&lt;TKey,TValue&gt;】约束。</param>
        /// <param name="typeArguments">泛型【TKey,TValue】约束。</param>
        /// <returns></returns>
        protected override Func <object, TResult> ByObjectToICollectionKeyValuePair <TResult>(Type sourceType, Type conversionType, Type typeArgument, Type[] typeArguments)
        {
            var typeStore = TypeItem.Get(sourceType);

            var list = new List <Expression>();

            var listKvType = typeof(List <>).MakeGenericType(typeArgument);

            var resultExp = Variable(listKvType);

            var targetExp = Variable(sourceType);

            var sourceExp = Parameter(typeof(object));

            var method = listKvType.GetMethod("Add", new Type[] { typeArgument });

            list.Add(Assign(targetExp, Convert(sourceExp, sourceType)));

            var methodCtor = ServiceCtor.Method;

            var bodyExp = methodCtor.IsStatic ?
                          Call(null, methodCtor, Constant(listKvType)) :
                          Call(Constant(ServiceCtor.Target), methodCtor, Constant(listKvType));

            list.Add(Assign(resultExp, Convert(bodyExp, listKvType)));

            var typeStore2 = TypeItem.Get(typeArgument);

            var ctorSotre = typeStore2.ConstructorStores.Where(x => x.ParameterStores.Count == 2).First();

            if (Kind == PatternKind.Property || Kind == PatternKind.All)
            {
                typeStore.PropertyStores
                .Where(x => x.CanRead)
                .ForEach(info =>
                {
                    list.Add(Call(resultExp, method, New(ctorSotre.Member, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Property(targetExp, info.Member), typeArguments[1]))));
                });
            }

            if (Kind == PatternKind.Field || Kind == PatternKind.All)
            {
                typeStore.FieldStores
                .Where(x => x.CanRead)
                .ForEach(info =>
                {
                    list.Add(Call(resultExp, method, New(ctorSotre.Member, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Field(targetExp, info.Member), typeArguments[1]))));
                });
            }

            list.Add(Convert(resultExp, conversionType));

            var lamdaExp = Lambda <Func <object, TResult> >(Block(new[] { targetExp, resultExp }, list), sourceExp);

            return(lamdaExp.Compile());
        }
Beispiel #2
0
        /// <summary>
        ///  解决 IEnumarable&lt;T&gt; 到 泛型约束类的转换。
        /// </summary>
        /// <typeparam name="TResult">目标类型。</typeparam>
        /// <param name="sourceType">源类型。</param>
        /// <param name="conversionType">目标类型。</param>
        /// <param name="interfaceType">接口类型。</param>
        /// <param name="typeArguments">方向约束。</param>
        /// <returns></returns>
        protected virtual Func <object, TResult> ByEnumarableKeyValuePairToObject <TResult>(Type sourceType, Type conversionType, Type interfaceType, Type[] typeArguments)
        {
            var typeStore = TypeItem.Get(conversionType);

            if (typeStore.ConstructorStores.Any(x => x.ParameterStores.Count == 0))
            {
                return(ByEnumarableKeyValuePairToCommon <TResult>(typeStore, sourceType, conversionType, interfaceType, typeArguments));
            }

            return(ByEnumarableKeyValuePairToComplex <TResult>(typeStore, sourceType, conversionType, interfaceType, typeArguments));
        }
Beispiel #3
0
        /// <summary>
        /// 解决 对象 到类似 IDictionary&lt;TKey,TValue&gt; 的转换。
        /// </summary>
        /// <typeparam name="TResult">目标类型。</typeparam>
        /// <param name="sourceType">源类型。</param>
        /// <param name="conversionType">目标类型。</param>
        /// <param name="typeArguments">泛型【TKey,TValue】约束。</param>
        /// <returns></returns>
        protected override Func <object, TResult> ByObjectToDictionaryLike <TResult>(Type sourceType, Type conversionType, Type[] typeArguments)
        {
            var typeStore = TypeItem.Get(sourceType);

            var list = new List <Expression>();

            var resultExp = Variable(conversionType);

            var targetExp = Variable(sourceType);

            var sourceExp = Parameter(typeof(object));

            var method = conversionType.GetMethod("Add", typeArguments);

            list.Add(Assign(targetExp, Convert(sourceExp, sourceType)));

            var methodCtor = ServiceCtor.Method;

            var bodyExp = methodCtor.IsStatic ?
                          Call(null, methodCtor, Constant(conversionType)) :
                          Call(Constant(ServiceCtor.Target), methodCtor, Constant(conversionType));

            list.Add(Assign(resultExp, Convert(bodyExp, conversionType)));

            if (Kind == PatternKind.Property || Kind == PatternKind.All)
            {
                typeStore.PropertyStores
                .Where(x => x.CanRead)
                .ForEach(info =>
                {
                    list.Add(Call(resultExp, method, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Property(targetExp, info.Member), typeArguments[1])));
                });
            }

            if (Kind == PatternKind.Field || Kind == PatternKind.All)
            {
                typeStore.FieldStores
                .Where(x => x.CanRead)
                .ForEach(info =>
                {
                    list.Add(Call(resultExp, method, ConvertTo(Constant(info.Naming), typeArguments[0]), ConvertTo(Field(targetExp, info.Member), typeArguments[1])));
                });
            }

            list.Add(resultExp);

            var lamdaExp = Lambda <Func <object, TResult> >(Block(new[] { targetExp, resultExp }, list), sourceExp);

            return(lamdaExp.Compile());
        }
Beispiel #4
0
        /// <summary>
        /// 映射查询(生成“<typeparamref name="TResult"/>”类型的查询表达式)。
        /// 注:名称相同(支持<see cref="NamingAttribute"/>比较),且可读写的属性映射。如:x => new YueClass { Id = x.Id, Name = x.Name }。
        /// </summary>
        /// <typeparam name="TResult">查询结果。</typeparam>
        /// <param name="source">数据源。</param>
        /// <returns></returns>
        public static IQueryable <TResult> Map <TResult>(this IQueryable source) where TResult : class, new()
        {
            if (source is IQueryable <TResult> queryable)
            {
                return(queryable);
            }

            var conversionType = typeof(TResult);
            var elementType    = source.ElementType;

            return(source.Provider.CreateQuery <TResult>(Expressions.GetOrAdd(((long)elementType.MetadataToken << 31) + conversionType.MetadataToken, _ =>
            {
                var typeItem = TypeItem.Get(conversionType);
                var typeItem2 = TypeItem.Get(elementType);

                var parameterExp = Parameter(elementType, "x");

                var list = new List <MemberBinding>();

                typeItem.PropertyStores
                .Where(x => x.CanWrite && x.CanRead)
                .ForEach(x =>
                {
                    var propItem = typeItem2.PropertyStores
                                   .FirstOrDefault(y => y.Name == x.Name && y.MemberType == x.MemberType && y.CanRead) ?? typeItem2
                                   .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Naming == x.Naming) ?? typeItem2
                                   .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Name == x.Naming) ?? typeItem2
                                   .PropertyStores.FirstOrDefault(y => y.MemberType == x.MemberType && y.CanRead && y.Naming == x.Name);

                    if (propItem is null || propItem.Ignore)
                    {
                        return;
                    }

                    list.Add(Bind(x.Member, Property(parameterExp, propItem.Member)));
                });

                var memberInit = MemberInit(New(typeItem.Type), list);

                var lambdaEx = Lambda(memberInit, parameterExp);

                return Call(SelectMethod.MakeGenericMethod(elementType, conversionType), new Expression[2] {
                    source.Expression,
                    lambdaEx
                });
            })));
Beispiel #5
0
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

            var typeStore = TypeItem.Get(config.GetType());

            var propertyStore = typeStore.PropertyStores.First(x => x.Name == "Services");

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
                );
        }
Beispiel #6
0
            public string[] Where <TColumn>(Expression <Func <TEntity, TColumn> > lamda)
            {
                if (lamda is null)
                {
                    throw new ArgumentNullException(nameof(lamda));
                }

                var parameter = lamda.Parameters[0];

                var body = lamda.Body;

                switch (body.NodeType)
                {
                case ExpressionType.Constant when body is ConstantExpression constant:
                    switch (constant.Value)
                    {
                    case string text:
                        return(text.Split(',', ' '));

                    case string[] arr:
                        return(arr);

                    default:
                        throw new NotImplementedException();
                    }

                case ExpressionType.MemberAccess when body is MemberExpression member:
                    return(new string[] { member.Member.Name });

                case ExpressionType.MemberInit when body is MemberInitExpression memberInit:
                    return(memberInit.Bindings.Select(x => x.Member.Name).ToArray());

                case ExpressionType.New when body is NewExpression newExpression:
                    return(newExpression.Members.Select(x => x.Name).ToArray());

                case ExpressionType.Parameter:
                    var storeItem = TypeItem.Get(parameter.Type);
                    return(storeItem.PropertyStores
                           .Where(x => x.CanRead)
                           .Select(x => x.Name)
                           .ToArray());

                default:
                    throw new NotSupportedException($"不支持表达式({lamda})!");
                }
            }
Beispiel #7
0
    /// <summary>
    /// 获取枚举描述。
    /// </summary>
    /// <typeparam name="TEnum">枚举类型。</typeparam>
    /// <param name="enum">枚举值。</param>
    /// <exception cref="ArgumentException">参数不是枚举类型。</exception>
    /// <returns></returns>
    public static string GetText <TEnum>(this TEnum @enum) where TEnum : struct
    {
        var type = typeof(TEnum);

        if (!type.IsEnum)
        {
            throw new ArgumentException("参数类型不是枚举!");
        }

        var typeStore = TypeItem.Get <TEnum>();

        string enumStr = @enum.ToString();

        if (typeStore.IsDefined <FlagsAttribute>())
        {
            var values = enumStr.Split(',').Select(x => x.Trim());

            if (!values.All(x => typeStore.FieldStores.Any(y => string.Equals(y.Name, x, StringComparison.InvariantCultureIgnoreCase))))
            {
                return("N/A");
            }

            return(string.Join("|", typeStore.FieldStores
                               .Where(x => values.Any(y => string.Equals(y, x.Name, StringComparison.InvariantCultureIgnoreCase)))
                               .Select(x =>
            {
                var desc2 = x.GetCustomAttribute <DescriptionAttribute>();

                return desc2 is null ? x.Name : desc2.Description;
            })));
        }

        var field = typeStore.FieldStores.FirstOrDefault(x => x.Name == enumStr);

        if (field is null)
        {
            return("N/A");
        }

        var desc = field.GetCustomAttribute <DescriptionAttribute>();

        return(desc is null ? field.Name : desc.Description);
    }
Beispiel #8
0
        /// <summary>
        /// 静态构造函数。
        /// </summary>
        static AdapterFormatter()
        {
            var contextType = typeof(T);

            var typeStore = TypeItem.Get(contextType);

            var matchType = typeof(Match);
            var groupType = typeof(Group);

            var contextExp   = Parameter(contextType, "context");
            var parameterExp = Parameter(matchType, "item");

            var getGroupMethod = GetMethodInfo(GetGroup);

            var checkGroupMethod = GetMethodInfo(CheckGroup);

            typeStore.MethodStores
            .Where(x => x.IsPublic && !x.IsStatic && x.Member.DeclaringType == contextType && x.Member.ReturnType == typeof(string) && x.ParameterStores.Count > 0)
            .OrderByDescending(x => x.ParameterStores.Count)
            .ForEach(x =>
            {
                if (!x.ParameterStores.All(y => y.ParameterType == matchType || y.ParameterType == groupType || y.ParameterType == typeof(string) || y.ParameterType == typeof(bool)))
                {
                    throw new NotSupportedException("仅支持类型System.Text.RegularExpressions.Match、System.Text.RegularExpressions.Group、System.String、System.Boolean类型的映射。");
                }

                var conditions  = new List <Expression>();
                var variables   = new List <ParameterExpression>();
                var arguments   = new List <Expression>();
                var expressions = new List <Expression>();

                x.ParameterStores.ForEach(y =>
                {
                    if (y.ParameterType == matchType)
                    {
                        arguments.Add(parameterExp);
                    }
                    else
                    {
                        var groupExp = Variable(groupType, y.Name);

                        variables.Add(groupExp);

                        expressions.Add(Assign(groupExp, Call(null, getGroupMethod, parameterExp, Constant(y.Name))));

                        if (y.ParameterType == groupType)
                        {
                            conditions.Add(Property(groupExp, "Success"));

                            arguments.Add(groupExp);
                        }
                        else
                        {
                            if (y.ParameterType == typeof(bool))
                            {
                                arguments.Add(Property(groupExp, "Success"));
                            }
                            else
                            {
                                arguments.Add(Property(groupExp, "Value"));

                                conditions.Add(Call(null, checkGroupMethod, groupExp));
                            }
                        }
                    }
                });

                var adapter = new Adapter();

                var enumerator = conditions.GetEnumerator();

                if (enumerator.MoveNext())
                {
                    var condition = enumerator.Current;

                    while (enumerator.MoveNext())
                    {
                        condition = AndAlso(condition, enumerator.Current);
                    }

                    var invoke = Lambda <Func <Match, bool> >(Block(variables, expressions.Concat(new Expression[1] {
                        condition
                    })), parameterExp);

                    adapter.CanConvert = invoke.Compile();
                }

                expressions.Add(Call(contextExp, x.Member, arguments));

                var lamdaExp = Lambda <Func <T, Match, string> >(Block(variables, expressions), contextExp, parameterExp);

                adapter.Convert = lamdaExp.Compile();

                AdapterCache.Add(adapter);
            });
        }
Beispiel #9
0
        /// <inheritdoc />
        protected override void VisitCore(MethodCallExpression node)
        {
            string name = node.Method.Name;

            if (isNoPackage)
            {
                switch (name)
                {
                case MethodCall.TimeOut:
                case MethodCall.From:
                case MethodCall.Any:
                case MethodCall.All:
                case MethodCall.Contains:
                case MethodCall.Union:
                case MethodCall.Concat:
                case MethodCall.Except:
                case MethodCall.Intersect:
                    break;

                default:
                    isNoPackage = false;
                    break;
                }
            }


            switch (name)
            {
            case MethodCall.ElementAt:
            case MethodCall.ElementAtOrDefault:

                base.Visit(node.Arguments[0]);

                int index = (int)node.Arguments[1].GetValueFromExpression();

                if (index < 0)
                {
                    throw new IndexOutOfRangeException();
                }

                if (this.take > 0 && index < this.take)
                {
                    throw new IndexOutOfRangeException();
                }

                this.take = 1;

                this.skip += index;

                break;

            case MethodCall.Take:
            case MethodCall.TakeLast:

                if (useAggregation)
                {
                    throw new DSyntaxErrorException($"使用聚合函数时,禁止使用分页函数({name})!");
                }

                if (name == MethodCall.TakeLast)
                {
                    reverseOrder ^= true;
                }

                int take = (int)node.Arguments[1].GetValueFromExpression();

                if (take < 1)
                {
                    throw new ArgumentOutOfRangeException($"使用{name}函数,参数值必须大于零!");
                }

                if (this.take > 0 && take < this.take)
                {
                    throw new IndexOutOfRangeException();
                }

                if (this.skip > -1)
                {
                    if (this.skip > take)
                    {
                        throw new IndexOutOfRangeException();
                    }

                    take -= this.skip;
                }

                if (this.take == -1)
                {
                    this.take = take;
                }

                base.Visit(node.Arguments[0]);

                if (!useOrderBy && name == MethodCall.TakeLast)
                {
                    throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!");
                }

                break;

            case MethodCall.First:
            case MethodCall.FirstOrDefault:
            case MethodCall.Single:
            case MethodCall.SingleOrDefault:

                // TOP(1)
                this.take = 1;

                if (node.Arguments.Count > 1)
                {
                    VisitCondition(node);
                }
                else
                {
                    Visit(node.Arguments[0]);
                }

                break;

            case MethodCall.Last:
            case MethodCall.LastOrDefault:

                // TOP(..)
                this.take = 1;

                reverseOrder ^= true;

                if (node.Arguments.Count > 1)
                {
                    VisitCondition(node);
                }
                else
                {
                    base.Visit(node.Arguments[0]);
                }

                if (!useOrderBy)
                {
                    throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!");
                }

                break;

            case MethodCall.Max:
                buildSelect    = false;
                buildedSelect  = true;
                useAggregation = true;
                using (var visitor = new MaxVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Min:
                buildSelect    = false;
                buildedSelect  = true;
                useAggregation = true;
                using (var visitor = new MinVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Sum:
                buildSelect    = false;
                buildedSelect  = true;
                useAggregation = true;
                using (var visitor = new SumVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Average:
                buildSelect    = false;
                buildedSelect  = true;
                useAggregation = true;
                using (var visitor = new AverageVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Count:
            case MethodCall.LongCount:
                useCount       = true;
                buildSelect    = false;
                buildedSelect  = true;
                useAggregation = true;
                using (var visitor = new CountVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Skip:
            case MethodCall.SkipLast:

                if (useAggregation)
                {
                    throw new DSyntaxErrorException($"使用聚合函数时,禁止使用分页函数({name})!");
                }

                if (name == MethodCall.SkipLast)
                {
                    reverseOrder ^= true;
                }

                int skip = (int)node.Arguments[1].GetValueFromExpression();

                if (skip < 0)
                {
                    throw new ArgumentOutOfRangeException($"使用({name})函数,参数值不能小于零!");
                }

                if (this.skip == -1)
                {
                    this.skip = skip;
                }
                else
                {
                    this.skip += skip;
                }

                base.Visit(node.Arguments[0]);

                if (!useOrderBy && name == MethodCall.SkipLast)
                {
                    throw new DSyntaxErrorException($"使用函数({name})时,必须使用排序函数(OrderBy/OrderByDescending)!");
                }

                break;

            case MethodCall.Reverse:

                reverseOrder ^= true;

                base.Visit(node.Arguments[0]);

                if (!useOrderBy)
                {
                    throw new DSyntaxErrorException($"使用函数“{name}”时,必须使用排序函数(OrderBy/OrderByDescending)!");
                }

                break;

            case MethodCall.GroupBy:
            case MethodCall.Where when node.Arguments[0].Type.IsGroupingQueryable():
            case MethodCall.TakeWhile when node.Arguments[0].Type.IsGroupingQueryable():
            case MethodCall.SkipWhile when node.Arguments[0].Type.IsGroupingQueryable():

                if (name == MethodCall.GroupBy)
                {
                    castCache.Add(node.Type.GetGenericArguments().First(), TypeToEntryType(node.Arguments[0].Type));
                }

                if (!useGroupBy)
                {
                    byVisitor = new GroupByVisitor(this, defaultCache, groupByExpressions);
                }

                useGroupBy = true;

                byVisitor.Startup(node);

                break;

            case MethodCall.Select:

                if (useCount)
                {
                    base.Visit(node.Arguments[0]);

                    break;
                }

                if (!buildSelect)
                {
                    throw new DSyntaxErrorException($"请将函数“{name}”置于查询最后一个包含入参的函数之后!");
                }

                buildSelect = buildFrom = false;

                writer.Select();

                Workflow(() =>
                {
                    buildedSelect = true;

                    if (isDistinct)
                    {
                        writer.Distinct();
                    }

                    inSelect = true;

                    Visit(node.Arguments[1]);

                    inSelect = false;

                    writer.From();

                    if (!hasJoin && !hasCombination)
                    {
                        WriteTableName(node.Arguments[0].Type);
                    }
                }, () => base.Visit(node.Arguments[0]));

                break;

            case MethodCall.SelectMany when node.Arguments.Count == 3:

                hasJoin = true;

                var parameterExp = Join(node.Arguments[2], true);

                bool DoneLeftJoin(ParameterExpression parameter, Expression expression)
                {
                    if (expression.NodeType == ExpressionType.MemberAccess)
                    {
                        return(false);
                    }

                    switch (expression)
                    {
                    case UnaryExpression unary:
                        return(DoneLeftJoin(parameter, unary.Operand));

                    case LambdaExpression lambda when lambda.Parameters.Count == 1:
                        return(DoneLeftJoin(parameter, lambda.Body));

                    case MethodCallExpression methodCall when methodCall.Method.Name == MethodCall.DefaultIfEmpty:

                        if (methodCall.Arguments.Count > 1)
                        {
                            defaultCache.Add(Tuple.Create(parameter.Type, parameter.Name), methodCall.Arguments[1]);
                        }

                        return(true);

                    default:
                        throw new DSyntaxErrorException();
                    }
                }

                using (var visitor = new GroupJoinVisitor(this, parameterExp, DoneLeftJoin(parameterExp, node.Arguments[1])))
                {
                    visitor.Startup(node.Arguments[0]);
                }

                buildTable = false;

                break;

            case MethodCall.Distinct:

                if (buildedSelect)
                {
                    throw new DSyntaxErrorException($"函数“{name}”未生效!");
                }

                isDistinct = true;

                base.Visit(node.Arguments[0]);

                break;

            case MethodCall.Cast:
            case MethodCall.OfType:
                Type type = node.Type
                            .GetGenericArguments()
                            .First();

                if (type.IsValueType || type == typeof(string) || typeof(IEnumerable).IsAssignableFrom(type))
                {
                    throw new TypeAccessInvalidException($"“{node.Method.Name}”函数泛型参数类型不能是值类型、字符串类型或迭代类型!");
                }

                var objExp = node.Arguments[0];

                var originalType = objExp.Type;

                if (node.Type == originalType)
                {
                    base.Visit(objExp);

                    break;
                }

                useCast = true;

                if (!castCache.ContainsKey(type))
                {
                    castCache.Add(type, TypeToEntryType(originalType));
                }

                var entry = TypeItem.Get(type);

                if (memberFilters.Count == 0)
                {
                    memberFilters.AddRange(entry.PropertyStores
                                           .Where(x => x.CanRead && x.CanWrite)
                                           .Select(x => x.Name.ToLower()));
                }
                else     //? 取交集
                {
                    memberFilters = memberFilters
                                    .Intersect(entry.PropertyStores
                                               .Where(x => x.CanRead && x.CanWrite)
                                               .Select(x => x.Name.ToLower()))
                                    .ToList();
                }

                if (memberFilters.Count == 0)
                {
                    throw new DException("未指定查询字段!");
                }

                base.Visit(objExp);

                break;

            case MethodCall.OrderBy:
            case MethodCall.ThenBy:
            case MethodCall.OrderByDescending:
            case MethodCall.ThenByDescending:

                useOrderBy = true;

                if (useAggregation)
                {
                    base.Visit(node.Arguments[0]);

                    break;
                }

                bool thatReverseOrder = reverseOrder;

                Workflow(() => writer.UsingSort(() =>
                {
                    orderBySwitch.OrderBy();

                    base.Visit(node.Arguments[1]);

                    if (thatReverseOrder ^ node.Method.Name.EndsWith("Descending"))
                    {
                        writer.Descending();
                    }
                }), () => base.Visit(node.Arguments[0]));

                break;

            case MethodCall.Join:

                hasJoin = true;

                Join(node.Arguments[2], false);

                Join(node.Arguments[3], true);

                using (var visitor = new JoinVisitor(this))
                {
                    visitor.Startup(node);
                }

                buildTable = false;
                break;

            case MethodCall.Any:
                isExists = true;
                using (var visitor = new AnyVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.All:
                isExists = true;
                using (var visitor = new AllVisitor(this))
                {
                    visitor.Startup(node);
                }
                break;

            case MethodCall.Union:
            case MethodCall.Concat:
            case MethodCall.Except:
            case MethodCall.Intersect:

                buildTable     = buildFrom = false;
                hasCombination = true;

                if (isNoPackage)
                {
                    buildSelect   = false;
                    buildedSelect = true;
                    using (var visitor = new CombinationVisitor(this))
                    {
                        visitor.Startup(node);
                    }

                    break;
                }

                string prefix = "x";

                if (buildSelect)
                {
                    buildSelect = false;

                    var tableInfo = MakeTableInfo(node.Arguments[0].Type);

                    Workflow(() =>
                    {
                        buildedSelect = true;

                        writer.Select();

                        if (isDistinct)
                        {
                            writer.Distinct();
                        }

                        WriteMembers(prefix, FilterMembers(tableInfo.ReadOrWrites));
                    }, Done);

                    break;
                }

                Done();

                break;

                void Done()
                {
                    writer.From();

                    writer.OpenBrace();

                    using (var visitor = new CombinationVisitor(this))
                    {
                        visitor.Startup(node);
                    }

                    writer.CloseBrace();

                    writer.WhiteSpace();

                    writer.Name(prefix = GetEntryAlias(node.Arguments[0].Type, "x"));
                }

            default:
                base.VisitCore(node);

                break;
            }

            ParameterExpression Join(Expression expression, bool isJoin)
            {
                switch (expression)
                {
                case UnaryExpression unary:
                    return(Join(unary.Operand, isJoin));

                case LambdaExpression lambda when lambda.Parameters.Count == 1 || lambda.Parameters.Count == 2:
#if NETSTANDARD2_1_OR_GREATER
                    var parameter = lambda.Parameters[^ 1];