diff Source/Data/Linq/Builder/TakeSkipBuilder.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Data/Linq/Builder/TakeSkipBuilder.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace BLToolkit.Data.Linq.Builder
+{
+	using BLToolkit.Linq;
+	using Data.Sql;
+
+	class TakeSkipBuilder : MethodCallBuilder
+	{
+		protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
+		{
+			return methodCall.IsQueryable("Skip", "Take");
+		}
+
+		protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
+		{
+			var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
+
+			var arg = methodCall.Arguments[1].Unwrap();
+
+			if (arg.NodeType == ExpressionType.Lambda)
+				arg = ((LambdaExpression)arg).Body.Unwrap();
+
+			var expr = builder.ConvertToSql(sequence, arg, false);
+
+			if (methodCall.Method.Name == "Take")
+			{
+				BuildTake(builder, sequence, expr);
+			}
+			else
+			{
+				BuildSkip(builder, sequence, sequence.SqlQuery.Select.SkipValue, expr);
+			}
+
+			return sequence;
+		}
+
+		protected override SequenceConvertInfo Convert(
+			ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
+		{
+			var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), null);
+
+			if (info != null)
+			{
+				info.Expression =
+					Expression.Call(
+						methodCall.Method.DeclaringType,
+						methodCall.Method.Name,
+						new[] { info.Expression.Type.GetGenericArguments()[0] },
+						info.Expression, methodCall.Arguments[1]);
+				info.Parameter  = param;
+
+				return info;
+			}
+
+			return null;
+		}
+
+		static void BuildTake(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression expr)
+		{
+			var sql = sequence.SqlQuery;
+
+			builder.SqlProvider.SqlQuery = sql;
+
+			sql.Select.Take(expr);
+
+			if (sql.Select.SkipValue != null && builder.SqlProvider.IsTakeSupported && !builder.SqlProvider.IsSkipSupported)
+			{
+				if (sql.Select.SkipValue is SqlParameter && sql.Select.TakeValue is SqlValue)
+				{
+					var skip = (SqlParameter)sql.Select.SkipValue;
+					var parm = (SqlParameter)sql.Select.SkipValue.Clone(new Dictionary<ICloneableElement,ICloneableElement>(), _ => true);
+
+					parm.SetTakeConverter((int)((SqlValue)sql.Select.TakeValue).Value);
+
+					sql.Select.Take(parm);
+
+					var ep = (from pm in builder.CurrentSqlParameters where pm.SqlParameter == skip select pm).First();
+
+					ep = new ParameterAccessor
+					{
+						Expression   = ep.Expression,
+						Accessor     = ep.Accessor,
+						SqlParameter = parm
+					};
+
+					builder.CurrentSqlParameters.Add(ep);
+				}
+				else
+					sql.Select.Take(builder.Convert(
+						sequence,
+						new SqlBinaryExpression(typeof(int), sql.Select.SkipValue, "+", sql.Select.TakeValue, Precedence.Additive)));
+			}
+
+			if (!builder.SqlProvider.TakeAcceptsParameter)
+			{
+				var p = sql.Select.TakeValue as SqlParameter;
+
+				if (p != null)
+					p.IsQueryParameter = false;
+			}
+		}
+
+		static void BuildSkip(ExpressionBuilder builder, IBuildContext sequence, ISqlExpression prevSkipValue, ISqlExpression expr)
+		{
+			var sql = sequence.SqlQuery;
+
+			builder.SqlProvider.SqlQuery = sql;
+
+			sql.Select.Skip(expr);
+
+			builder.SqlProvider.SqlQuery = sql;
+
+			if (sql.Select.TakeValue != null)
+			{
+				if (builder.SqlProvider.IsSkipSupported || !builder.SqlProvider.IsTakeSupported)
+					sql.Select.Take(builder.Convert(
+						sequence,
+						new SqlBinaryExpression(typeof(int), sql.Select.TakeValue, "-", sql.Select.SkipValue, Precedence.Additive)));
+
+				if (prevSkipValue != null)
+					sql.Select.Skip(builder.Convert(
+						sequence,
+						new SqlBinaryExpression(typeof(int), prevSkipValue, "+", sql.Select.SkipValue, Precedence.Additive)));
+			}
+
+			if (!builder.SqlProvider.TakeAcceptsParameter)
+			{
+				var p = sql.Select.SkipValue as SqlParameter;
+
+				if (p != null)
+					p.IsQueryParameter = false;
+			}
+		}
+	}
+}