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 } |
