Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/FirstSingleBuilder.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; | |
3 using System.Linq.Expressions; | |
4 | |
5 namespace BLToolkit.Data.Linq.Builder | |
6 { | |
7 using BLToolkit.Linq; | |
8 using Data.Sql; | |
9 using Reflection; | |
10 | |
11 class FirstSingleBuilder : MethodCallBuilder | |
12 { | |
13 public static string[] MethodNames = new[] { "First", "FirstOrDefault", "Single", "SingleOrDefault" }; | |
14 | |
15 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
16 { | |
17 return | |
18 methodCall.IsQueryable(MethodNames) && | |
19 methodCall.Arguments.Count == 1; | |
20 } | |
21 | |
22 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
23 { | |
24 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); | |
25 var take = 0; | |
26 | |
27 if (!buildInfo.IsSubQuery || builder.SqlProvider.IsSubQueryTakeSupported) | |
28 switch (methodCall.Method.Name) | |
29 { | |
30 case "First" : | |
31 case "FirstOrDefault" : | |
32 take = 1; | |
33 break; | |
34 | |
35 case "Single" : | |
36 case "SingleOrDefault" : | |
37 if (!buildInfo.IsSubQuery) | |
38 take = 2; | |
39 break; | |
40 } | |
41 | |
42 if (take != 0) | |
43 builder.BuildTake(sequence, new SqlValue(take)); | |
44 | |
45 return new FirstSingleContext(buildInfo.Parent, sequence, methodCall); | |
46 } | |
47 | |
48 protected override SequenceConvertInfo Convert( | |
49 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) | |
50 { | |
51 if (methodCall.Arguments.Count == 2) | |
52 { | |
53 var predicate = (LambdaExpression)methodCall.Arguments[1].Unwrap(); | |
54 var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), predicate.Parameters[0]); | |
55 | |
56 if (info != null) | |
57 { | |
58 info.Expression = methodCall.Convert(ex => ConvertMethod(methodCall, 0, info, predicate.Parameters[0], ex)); | |
59 info.Parameter = param; | |
60 | |
61 return info; | |
62 } | |
63 } | |
64 else | |
65 { | |
66 var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), null); | |
67 | |
68 if (info != null) | |
69 { | |
70 info.Expression = methodCall.Convert(ex => ConvertMethod(methodCall, 0, info, null, ex)); | |
71 info.Parameter = param; | |
72 | |
73 return info; | |
74 } | |
75 } | |
76 | |
77 return null; | |
78 } | |
79 | |
80 public class FirstSingleContext : SequenceContextBase | |
81 { | |
82 public FirstSingleContext(IBuildContext parent, IBuildContext sequence, MethodCallExpression methodCall) | |
83 : base(parent, sequence, null) | |
84 { | |
85 _methodCall = methodCall; | |
86 } | |
87 | |
88 readonly MethodCallExpression _methodCall; | |
89 | |
90 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) | |
91 { | |
92 Sequence.BuildQuery(query, queryParameter); | |
93 | |
94 switch (_methodCall.Method.Name) | |
95 { | |
96 case "First" : query.GetElement = (ctx, db, expr, ps) => query.GetIEnumerable(ctx, db, expr, ps).First(); break; | |
97 case "FirstOrDefault" : query.GetElement = (ctx, db, expr, ps) => query.GetIEnumerable(ctx, db, expr, ps).FirstOrDefault(); break; | |
98 case "Single" : query.GetElement = (ctx, db, expr, ps) => query.GetIEnumerable(ctx, db, expr, ps).Single(); break; | |
99 case "SingleOrDefault" : query.GetElement = (ctx, db, expr, ps) => query.GetIEnumerable(ctx, db, expr, ps).SingleOrDefault(); break; | |
100 } | |
101 } | |
102 | |
103 static object SequenceException() | |
104 { | |
105 return new object[0].First(); | |
106 } | |
107 | |
108 public override Expression BuildExpression(Expression expression, int level) | |
109 { | |
110 if (expression == null) | |
111 { | |
112 if (Builder.SqlProvider.IsApplyJoinSupported && Parent.SqlQuery.GroupBy.IsEmpty) | |
113 { | |
114 var join = SqlQuery.OuterApply(SqlQuery); | |
115 | |
116 Parent.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
117 | |
118 var expr = Sequence.BuildExpression(expression, level); | |
119 var idx = SqlQuery.Select.Add(new SqlValue(1)); | |
120 | |
121 idx = ConvertToParentIndex(idx, this); | |
122 | |
123 var defaultValue = _methodCall.Method.Name.EndsWith("OrDefault") ? | |
124 Expression.Constant(TypeHelper.GetDefaultValue(expr.Type), expr.Type) as Expression : | |
125 Expression.Convert( | |
126 Expression.Call( | |
127 null, | |
128 ReflectionHelper.Expressor<object>.MethodExpressor(_ => SequenceException())), | |
129 expr.Type); | |
130 | |
131 expr = Expression.Condition( | |
132 Expression.Call( | |
133 ExpressionBuilder.DataReaderParam, | |
134 ReflectionHelper.DataReader.IsDBNull, | |
135 Expression.Constant(idx)), | |
136 defaultValue, | |
137 expr); | |
138 | |
139 return expr; | |
140 } | |
141 | |
142 if (Sequence.IsExpression(null, level, RequestFor.Object).Result) | |
143 return Builder.BuildMultipleQuery(Parent, _methodCall); | |
144 | |
145 return Builder.BuildSql(_methodCall.Type, Parent.SqlQuery.Select.Add(SqlQuery)); | |
146 } | |
147 | |
148 throw new InvalidOperationException(); | |
149 } | |
150 | |
151 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) | |
152 { | |
153 return Sequence.ConvertToSql(expression, level + 1, flags); | |
154 } | |
155 | |
156 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) | |
157 { | |
158 return Sequence.ConvertToIndex(expression, level, flags); | |
159 } | |
160 | |
161 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag) | |
162 { | |
163 return Sequence.IsExpression(expression, level, requestFlag); | |
164 } | |
165 | |
166 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo) | |
167 { | |
168 throw new InvalidOperationException(); | |
169 } | |
170 } | |
171 } | |
172 } |