Mercurial > pub > bltoolkit
view Source/Data/Linq/Builder/TakeSkipBuilder.cs @ 9:1e85f66cf767 default tip
update bltoolkit
author | nickolay |
---|---|
date | Thu, 05 Apr 2018 20:53:26 +0300 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
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; } } } }