comparison Source/Data/Linq/Builder/CountBuilder.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
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 }