/// <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];
/// <inheritdoc /> public HavingVisitor(GroupByVisitor visitor, Dictionary <MemberInfo, Expression> groupByExpressions) : base(visitor) { this.visitor = visitor; this.groupByExpressions = groupByExpressions; }