From 033049d3df864559bc1453dac77bd0427e130add Mon Sep 17 00:00:00 2001 From: AlekseyMartynov Date: Sat, 6 May 2017 00:59:27 +0300 Subject: [PATCH] ready --- .../DataSourceExpressionBuilderTests.cs | 34 +++++++------- .../Extensions.cs | 29 ++++++++++++ .../DataSourceExpressionBuilder.cs | 47 ++++++------------- .../DataSourceLoader.cs | 21 +++++---- 4 files changed, 72 insertions(+), 59 deletions(-) create mode 100644 net/DevExtreme.AspNet.Data.Tests/Extensions.cs diff --git a/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs b/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs index 6129a24c..51a113e6 100644 --- a/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs +++ b/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs @@ -21,7 +21,7 @@ public void Build_SkipTake() { var expr = builder.BuildLoadExpr(); - Assert.Equal("data.Skip(111).Take(222)", expr.Body.ToString()); + Assert.Equal("data.Skip(111).Take(222)", expr.ToString()); } [Fact] @@ -32,7 +32,7 @@ public void Build_Filter() { var expr = builder.BuildLoadExpr(); - Assert.Equal("data.Where(obj => (obj > 123))", expr.Body.ToString()); + Assert.Equal("data.Where(obj => (obj > 123))", expr.ToString()); } [Fact] @@ -82,7 +82,7 @@ public void Build_Sorting() { }); var expr = builder.BuildLoadExpr(); - Assert.Equal("data.OrderBy(obj => obj.Item1).ThenByDescending(obj => obj.Item2)", expr.Body.ToString()); + Assert.Equal("data.OrderBy(obj => obj.Item1).ThenByDescending(obj => obj.Item2)", expr.ToString()); } [Fact] @@ -102,11 +102,11 @@ public void GroupingAddedToSorting() { Assert.Equal( "data.OrderBy(obj => obj.Item1).ThenByDescending(obj => obj.Item2).ThenBy(obj => obj.Item3)", - builder.BuildLoadExpr().Body.ToString() + builder.BuildLoadExpr().ToString() ); loadOptions.Sort = null; - Assert.Contains("OrderBy", builder.BuildLoadExpr().Body.ToString()); + Assert.Contains("OrderBy", builder.BuildLoadExpr().ToString()); } [Fact] @@ -118,7 +118,7 @@ public void MultiIntervalGroupsSortedOnce() { } }); - Assert.Equal("data.OrderBy(obj => obj)", builder.BuildLoadExpr().Body.ToString()); + Assert.Equal("data.OrderBy(obj => obj)", builder.BuildLoadExpr().ToString()); } [Fact] @@ -137,9 +137,6 @@ public void GuardNulls() { } }, true); - var expr = builder.BuildLoadExpr(); - var query = expr.Compile(); - var data = new[] { // filtered out null, @@ -151,9 +148,10 @@ public void GuardNulls() { // kept Tuple.Create(1, "zz", new DateTime(2000, 1, 2)), Tuple.Create(1, "zz", new DateTime(2000, 1, 1)) - }; + }.AsQueryable(); - var result = query(data.AsQueryable()).ToArray(); + var expr = builder.BuildLoadExpr(data.Expression); + var result = data.Provider.CreateQuery(expr).ToArray(); Assert.Equal(2, result.Length); } @@ -165,16 +163,16 @@ public void DefaultSort() { var builder = new DataSourceExpressionBuilder>(options, false); - Assert.Equal("data.OrderBy(obj => obj.Item1)", builder.BuildLoadExpr(false).Body.ToString()); + Assert.Equal("data.OrderBy(obj => obj.Item1)", builder.BuildLoadExpr(false).ToString()); options.Sort = new[] { new SortingInfo { Selector = "Item2" } }; - Assert.Equal("data.OrderBy(obj => obj.Item2).ThenBy(obj => obj.Item1)", builder.BuildLoadExpr(false).Body.ToString()); + Assert.Equal("data.OrderBy(obj => obj.Item2).ThenBy(obj => obj.Item1)", builder.BuildLoadExpr(false).ToString()); options.Sort[0].Selector = "Item1"; - Assert.Equal("data.OrderBy(obj => obj.Item1)", builder.BuildLoadExpr(false).Body.ToString()); + Assert.Equal("data.OrderBy(obj => obj.Item1)", builder.BuildLoadExpr(false).ToString()); } [Fact] @@ -190,7 +188,7 @@ public void NoUnnecessaryOrderingForRemoteGroups() { }; var builder = new DataSourceExpressionBuilder>(options, false); - var expr = builder.BuildLoadGroupsExpr().Body.ToString(); + var expr = builder.BuildLoadGroupsExpr().ToString(); Assert.True(expr.StartsWith("data.GroupBy")); } @@ -205,7 +203,7 @@ public void AlwaysOrderDataByPrimaryKey() { Assert.Equal( "data.OrderBy(obj => obj.Item2).ThenBy(obj => obj.Item1)", - builder.BuildLoadExpr().Body.ToString() + builder.BuildLoadExpr().ToString() ); } @@ -221,7 +219,7 @@ public void DefaultSortAndPrimaryKey() { Assert.Equal( "data.OrderBy(obj => obj.Item1)", - builder.BuildLoadExpr().Body.ToString() + builder.BuildLoadExpr().ToString() ); options.DefaultSort = "Item2"; @@ -229,7 +227,7 @@ public void DefaultSortAndPrimaryKey() { Assert.Equal( "data.OrderBy(obj => obj.Item3).ThenBy(obj => obj.Item2).ThenBy(obj => obj.Item1)", - builder.BuildLoadExpr().Body.ToString() + builder.BuildLoadExpr().ToString() ); } } diff --git a/net/DevExtreme.AspNet.Data.Tests/Extensions.cs b/net/DevExtreme.AspNet.Data.Tests/Extensions.cs new file mode 100644 index 00000000..3b8e9aec --- /dev/null +++ b/net/DevExtreme.AspNet.Data.Tests/Extensions.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace DevExtreme.AspNet.Data.Tests { + + static class Extensions { + + public static Expression BuildLoadExpr(this DataSourceExpressionBuilder builder, bool paginate = true) { + return builder.BuildLoadExpr(CreateSourceExpr(), paginate); + } + + public static Expression BuildCountExpr(this DataSourceExpressionBuilder builder) { + return builder.BuildCountExpr(CreateSourceExpr()); + } + + public static Expression BuildLoadGroupsExpr(this DataSourceExpressionBuilder builder) { + return builder.BuildLoadGroupsExpr(CreateSourceExpr()); + } + + static Expression CreateSourceExpr() { + return Expression.Parameter(typeof(IQueryable), "data"); + } + + } + +} diff --git a/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs b/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs index 2c216086..0ff539f6 100644 --- a/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs +++ b/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs @@ -18,65 +18,46 @@ public DataSourceExpressionBuilder(DataSourceLoadOptionsBase loadOptions, bool g _guardNulls = guardNulls; } - public Expression, IQueryable>> BuildLoadExpr(bool paginate = true) { - var param = CreateParam(); - return Expression.Lambda, IQueryable>>( - BuildCore(param, paginate: paginate), - param - ); + public Expression BuildLoadExpr(Expression source, bool paginate = true) { + return BuildCore(source, paginate: paginate); } - public Expression, int>> BuildCountExpr() { - var param = CreateParam(); - return Expression.Lambda, int>>( - BuildCore(param, isCountQuery: true), - param - ); + public Expression BuildCountExpr(Expression source) { + return BuildCore(source, isCountQuery: true); } - public Expression, IQueryable>> BuildLoadGroupsExpr() { - var param = CreateParam(); - return Expression.Lambda, IQueryable>>( - BuildCore(param, remoteGrouping: true), - param - ); + public Expression BuildLoadGroupsExpr(Expression source) { + return BuildCore(source, remoteGrouping: true); } - Expression BuildCore(ParameterExpression param, bool paginate = false, bool isCountQuery = false, bool remoteGrouping = false) { + Expression BuildCore(Expression expr, bool paginate = false, bool isCountQuery = false, bool remoteGrouping = false) { var queryableType = typeof(Queryable); var genericTypeArguments = new[] { typeof(T) }; - Expression body = param; - if(_loadOptions.HasFilter) - body = Expression.Call(queryableType, "Where", genericTypeArguments, body, Expression.Quote(new FilterExpressionCompiler(_guardNulls).Compile(_loadOptions.Filter))); + expr = Expression.Call(queryableType, "Where", genericTypeArguments, expr, Expression.Quote(new FilterExpressionCompiler(_guardNulls).Compile(_loadOptions.Filter))); if(!isCountQuery) { if(!remoteGrouping) { if(_loadOptions.HasAnySort) - body = new SortExpressionCompiler(_guardNulls).Compile(body, _loadOptions.GetFullSort()); + expr = new SortExpressionCompiler(_guardNulls).Compile(expr, _loadOptions.GetFullSort()); } else { - body = new RemoteGroupExpressionCompiler(_loadOptions.Group, _loadOptions.TotalSummary, _loadOptions.GroupSummary).Compile(body); + expr = new RemoteGroupExpressionCompiler(_loadOptions.Group, _loadOptions.TotalSummary, _loadOptions.GroupSummary).Compile(expr); } if(paginate) { if(_loadOptions.Skip > 0) - body = Expression.Call(queryableType, "Skip", genericTypeArguments, body, Expression.Constant(_loadOptions.Skip)); + expr = Expression.Call(queryableType, "Skip", genericTypeArguments, expr, Expression.Constant(_loadOptions.Skip)); if(_loadOptions.Take > 0) - body = Expression.Call(queryableType, "Take", genericTypeArguments, body, Expression.Constant(_loadOptions.Take)); + expr = Expression.Call(queryableType, "Take", genericTypeArguments, expr, Expression.Constant(_loadOptions.Take)); } } if(isCountQuery) - body = Expression.Call(queryableType, "Count", genericTypeArguments, body); - - return body; - } - + expr = Expression.Call(queryableType, "Count", genericTypeArguments, expr); - ParameterExpression CreateParam() { - return Expression.Parameter(typeof(IQueryable), "data"); + return expr; } } diff --git a/net/DevExtreme.AspNet.Data/DataSourceLoader.cs b/net/DevExtreme.AspNet.Data/DataSourceLoader.cs index ac8c4dbb..6c761419 100644 --- a/net/DevExtreme.AspNet.Data/DataSourceLoader.cs +++ b/net/DevExtreme.AspNet.Data/DataSourceLoader.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; namespace DevExtreme.AspNet.Data { @@ -20,7 +21,7 @@ public static object Load(IQueryable source, DataSourceLoadOptionsBase opt var builder = new DataSourceExpressionBuilder(options, isLinqToObjects); if(options.IsCountQuery) - return builder.BuildCountExpr().Compile()(source); + return ExecCount(builder, source); var accessor = new DefaultAccessor(); var result = new DataSourceLoadResult(); @@ -47,12 +48,12 @@ public static object Load(IQueryable source, DataSourceLoadOptionsBase opt options.DefaultSort = EFSorting.FindSortableMember(typeof(T)); var deferPaging = options.HasGroups || options.HasSummary && !canUseRemoteGrouping; - var queryResult = ExecQuery(builder.BuildLoadExpr(!deferPaging).Compile(), source, options); + var dataQuery = AppendExpr(source, builder.BuildLoadExpr(source.Expression, !deferPaging), options); - IEnumerable data = queryResult; + IEnumerable data = dataQuery; if(options.HasGroups) { - data = new GroupHelper(accessor).Group(queryResult, options.Group); + data = new GroupHelper(accessor).Group(dataQuery, options.Group); if(options.RequireGroupCount) { result.groupCount = (data as IList).Count; } @@ -64,7 +65,7 @@ public static object Load(IQueryable source, DataSourceLoadOptionsBase opt result.summary = groupingResult.Totals; } else { if(options.RequireTotalCount) - result.totalCount = builder.BuildCountExpr().Compile()(source); + result.totalCount = ExecCount(builder, source); if(options.HasSummary) { data = Buffer(data); @@ -95,8 +96,12 @@ static IEnumerable Buffer(IEnumerable data) { return data; } - static IQueryable ExecQuery(Func, IQueryable> query, IQueryable source, DataSourceLoadOptionsBase options) { - var result = query(source); + static int ExecCount(DataSourceExpressionBuilder builder, IQueryable source) { + return (int)source.Provider.Execute(builder.BuildCountExpr(source.Expression)); + } + + static IQueryable AppendExpr(IQueryable source, Expression expr, DataSourceLoadOptionsBase options) { + var result = source.Provider.CreateQuery(expr); #if DEBUG if(options.UseQueryableOnce) @@ -112,7 +117,7 @@ static IQueryable ExecQuery(Func, IQueryable> query, I static RemoteGroupingResult ExecRemoteGrouping(IQueryable source, DataSourceExpressionBuilder builder, DataSourceLoadOptionsBase options) { return RemoteGroupTransformer.Run( - ExecQuery(builder.BuildLoadGroupsExpr().Compile(), source, options), + AppendExpr(source, builder.BuildLoadGroupsExpr(source.Expression), options), options.HasGroups ? options.Group.Length : 0, options.TotalSummary, options.GroupSummary