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