comparison Source/Data/Linq/Builder/TakeSkipBuilder.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.Collections.Generic;
3 using System.Linq;
4 using System.Linq.Expressions;
5
6 namespace BLToolkit.Data.Linq.Builder
7 {
8 using BLToolkit.Linq;
9 using Data.Sql;
10
11 class TakeSkipBuilder : MethodCallBuilder
12 {
13 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
14 {
15 return methodCall.IsQueryable("Skip", "Take");
16 }
17
18 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
19 {
20 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
21
22 var arg = methodCall.Arguments[1].Unwrap();
23
24 if (arg.NodeType == ExpressionType.Lambda)
25 arg = ((LambdaExpression)arg).Body.Unwrap();
26
27 var expr = builder.ConvertToSql(sequence, arg, false);
28
29 if (methodCall.Method.Name == "Take")
30 {
31 BuildTake(builder, sequence, expr);
32 }
33 else
34 {
35 BuildSkip(builder, sequence, sequence.SqlQuery.Select.SkipValue, expr);
36 }
37
38 return sequence;
39 }
40
41 protected override SequenceConvertInfo Convert(
42 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
43 {
44 var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), null);
45
46 if (info != null)
47 {
48 info.Expression =
49 Expression.Call(
50 methodCall.Method.DeclaringType,
51 methodCall.Method.Name,
52 new[] { info.Expression.Type.GetGenericArguments()[0] },
53 info.Expression, methodCall.Arguments[1]);
54 info.Parameter = param;
55
56 return info;
57 }
58
59 return null;
60 }
61
62 static void BuildTake(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression expr)
63 {
64 var sql = sequence.SqlQuery;
65
66 builder.SqlProvider.SqlQuery = sql;
67
68 sql.Select.Take(expr);
69
70 if (sql.Select.SkipValue != null && builder.SqlProvider.IsTakeSupported && !builder.SqlProvider.IsSkipSupported)
71 {
72 if (sql.Select.SkipValue is SqlParameter && sql.Select.TakeValue is SqlValue)
73 {
74 var skip = (SqlParameter)sql.Select.SkipValue;
75 var parm = (SqlParameter)sql.Select.SkipValue.Clone(new Dictionary<ICloneableElement,ICloneableElement>(), _ => true);
76
77 parm.SetTakeConverter((int)((SqlValue)sql.Select.TakeValue).Value);
78
79 sql.Select.Take(parm);
80
81 var ep = (from pm in builder.CurrentSqlParameters where pm.SqlParameter == skip select pm).First();
82
83 ep = new ParameterAccessor
84 {
85 Expression = ep.Expression,
86 Accessor = ep.Accessor,
87 SqlParameter = parm
88 };
89
90 builder.CurrentSqlParameters.Add(ep);
91 }
92 else
93 sql.Select.Take(builder.Convert(
94 sequence,
95 new SqlBinaryExpression(typeof(int), sql.Select.SkipValue, "+", sql.Select.TakeValue, Precedence.Additive)));
96 }
97
98 if (!builder.SqlProvider.TakeAcceptsParameter)
99 {
100 var p = sql.Select.TakeValue as SqlParameter;
101
102 if (p != null)
103 p.IsQueryParameter = false;
104 }
105 }
106
107 static void BuildSkip(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression prevSkipValue, ISqlExpression expr)
108 {
109 var sql = sequence.SqlQuery;
110
111 builder.SqlProvider.SqlQuery = sql;
112
113 sql.Select.Skip(expr);
114
115 builder.SqlProvider.SqlQuery = sql;
116
117 if (sql.Select.TakeValue != null)
118 {
119 if (builder.SqlProvider.IsSkipSupported || !builder.SqlProvider.IsTakeSupported)
120 sql.Select.Take(builder.Convert(
121 sequence,
122 new SqlBinaryExpression(typeof(int), sql.Select.TakeValue, "-", sql.Select.SkipValue, Precedence.Additive)));
123
124 if (prevSkipValue != null)
125 sql.Select.Skip(builder.Convert(
126 sequence,
127 new SqlBinaryExpression(typeof(int), prevSkipValue, "+", sql.Select.SkipValue, Precedence.Additive)));
128 }
129
130 if (!builder.SqlProvider.TakeAcceptsParameter)
131 {
132 var p = sql.Select.SkipValue as SqlParameter;
133
134 if (p != null)
135 p.IsQueryParameter = false;
136 }
137 }
138 }
139 }