0
|
1 using System;
|
|
2 using System.Linq.Expressions;
|
|
3
|
|
4 namespace BLToolkit.Data.Linq.Builder
|
|
5 {
|
|
6 using BLToolkit.Linq;
|
|
7 using Data.Sql;
|
|
8
|
|
9 class CountBuilder : MethodCallBuilder
|
|
10 {
|
|
11 public static string[] MethodNames = new[] { "Count", "LongCount" };
|
|
12
|
|
13 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
14 {
|
|
15 return methodCall.IsQueryable(MethodNames);
|
|
16 }
|
|
17
|
|
18 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
19 {
|
|
20 var returnType = methodCall.Method.ReturnType;
|
|
21 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
|
|
22
|
|
23 if (sequence.SqlQuery != buildInfo.SqlQuery)
|
|
24 {
|
|
25 if (sequence is JoinBuilder.GroupJoinSubQueryContext)
|
|
26 {
|
|
27 var ctx = new CountContext(buildInfo.Parent, sequence, returnType)
|
|
28 {
|
|
29 SqlQuery = ((JoinBuilder.GroupJoinSubQueryContext)sequence).GetCounter(methodCall)
|
|
30 };
|
|
31
|
|
32 ctx.Sql = ctx.SqlQuery;
|
|
33 ctx.FieldIndex = ctx.SqlQuery.Select.Add(SqlFunction.CreateCount(returnType, ctx.SqlQuery), "cnt");
|
|
34
|
|
35 return ctx;
|
|
36 }
|
|
37
|
|
38 if (sequence is GroupByBuilder.GroupByContext)
|
|
39 {
|
|
40 return new CountContext(buildInfo.Parent, sequence, returnType)
|
|
41 {
|
|
42 Sql = SqlFunction.CreateCount(returnType, sequence.SqlQuery),
|
|
43 FieldIndex = -1
|
|
44 };
|
|
45 }
|
|
46 }
|
|
47
|
|
48 if (sequence.SqlQuery.Select.IsDistinct ||
|
|
49 sequence.SqlQuery.Select.TakeValue != null ||
|
|
50 sequence.SqlQuery.Select.SkipValue != null ||
|
|
51 !sequence.SqlQuery.GroupBy.IsEmpty)
|
|
52 {
|
|
53 sequence.ConvertToIndex(null, 0, ConvertFlags.Key);
|
|
54 sequence = new SubQueryContext(sequence);
|
|
55 }
|
|
56
|
|
57 if (sequence.SqlQuery.OrderBy.Items.Count > 0)
|
|
58 {
|
|
59 if (sequence.SqlQuery.Select.TakeValue == null && sequence.SqlQuery.Select.SkipValue == null)
|
|
60 sequence.SqlQuery.OrderBy.Items.Clear();
|
|
61 else
|
|
62 sequence = new SubQueryContext(sequence);
|
|
63 }
|
|
64
|
|
65 var context = new CountContext(buildInfo.Parent, sequence, returnType);
|
|
66
|
|
67 context.Sql = context.SqlQuery;
|
|
68 context.FieldIndex = context.SqlQuery.Select.Add(SqlFunction.CreateCount(returnType, context.SqlQuery), "cnt");
|
|
69
|
|
70 return context;
|
|
71 }
|
|
72
|
|
73 protected override SequenceConvertInfo Convert(
|
|
74 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
|
|
75 {
|
|
76 return null;
|
|
77 }
|
|
78
|
|
79 internal class CountContext : SequenceContextBase
|
|
80 {
|
|
81 public CountContext(IBuildContext parent, IBuildContext sequence, Type returnType)
|
|
82 : base(parent, sequence, null)
|
|
83 {
|
|
84 _returnType = returnType;
|
|
85 }
|
|
86
|
|
87 readonly Type _returnType;
|
|
88 private SqlInfo[] _index;
|
|
89
|
|
90 public int FieldIndex;
|
|
91 public ISqlExpression Sql;
|
|
92
|
|
93 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter)
|
|
94 {
|
|
95 var expr = Builder.BuildSql(_returnType, FieldIndex);
|
|
96 var mapper = Builder.BuildMapper<object>(expr);
|
|
97
|
|
98 query.SetElementQuery(mapper.Compile());
|
|
99 }
|
|
100
|
|
101 public override Expression BuildExpression(Expression expression, int level)
|
|
102 {
|
|
103 return Builder.BuildSql(_returnType, ConvertToIndex(expression, level, ConvertFlags.Field)[0].Index);
|
|
104 }
|
|
105
|
|
106 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
|
|
107 {
|
|
108 switch (flags)
|
|
109 {
|
|
110 case ConvertFlags.Field : return new[] { new SqlInfo { Query = Parent.SqlQuery, Sql = Sql } };
|
|
111 }
|
|
112
|
|
113 throw new InvalidOperationException();
|
|
114 }
|
|
115
|
|
116 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
|
|
117 {
|
|
118 switch (flags)
|
|
119 {
|
|
120 case ConvertFlags.Field :
|
|
121 return _index ?? (_index = new[]
|
|
122 {
|
|
123 new SqlInfo { Query = Parent.SqlQuery, Index = Parent.SqlQuery.Select.Add(Sql), Sql = Sql, }
|
|
124 });
|
|
125 }
|
|
126
|
|
127 throw new InvalidOperationException();
|
|
128 }
|
|
129
|
|
130 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag)
|
|
131 {
|
|
132 switch (requestFlag)
|
|
133 {
|
|
134 case RequestFor.Expression : return IsExpressionResult.True;
|
|
135 }
|
|
136
|
|
137 return IsExpressionResult.False;
|
|
138 }
|
|
139
|
|
140 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
|
|
141 {
|
|
142 return Sequence.GetContext(expression, level, buildInfo);
|
|
143 }
|
|
144
|
|
145 public override ISqlExpression GetSubQuery(IBuildContext context)
|
|
146 {
|
|
147 var query = context.SqlQuery;
|
|
148
|
|
149 if (query == SqlQuery)
|
|
150 {
|
|
151 var col = query.Select.Columns[query.Select.Columns.Count - 1];
|
|
152
|
|
153 query.Select.Columns.RemoveAt(query.Select.Columns.Count - 1);
|
|
154
|
|
155 return col.Expression;
|
|
156 }
|
|
157
|
|
158 return null;
|
|
159 }
|
|
160 }
|
|
161 }
|
|
162 }
|