diff --git a/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs b/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs index 73121243..7ae9c87d 100644 --- a/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs +++ b/net/DevExtreme.AspNet.Data.Tests/DataSourceExpressionBuilderTests.cs @@ -339,6 +339,39 @@ string BuildExpr(DataSourceLoadOptionsBase options) => Compat.CreateDataSourceEx }) ); } + + [Fact] + public void BuildGroupCountExpr_IntervalGrouping() { + string BuildExpr(DataSourceLoadOptionsBase options) => Compat.CreateDataSourceExpressionBuilder>(options) + .BuildGroupCountExpr() + .ToString(); + + Assert.Equal( + "data.Where(obj => (obj.Item1 == 1))" + + // "Convert" expression is displayed differently in the .NET Framework and .NET Core + // https://github.com/microsoft/referencesource/blob/ec9fa9ae770d522a5b5f0607898044b7478574a3/System.Core/Microsoft/Scripting/Ast/ExpressionStringBuilder.cs#L657 +#if NET4 + ".GroupBy(obj => new AnonType`1(I0 = Convert(obj.Item2.Year)))" + +#else + ".GroupBy(obj => new AnonType`1(I0 = Convert(obj.Item2.Year, Nullable`1)))" + +#endif + ".OrderBy(g => g.Key.I0)" + + ".Select(g => new AnonType`2(I0 = g.Count(), I1 = g.Key.I0))" + + ".Count()", + + BuildExpr(new SampleLoadOptions { + GuardNulls = false, + Filter = new[] { "Item1", "1" }, + RequireGroupCount = true, + Group = new[] { + new GroupingInfo { Selector = "Item2", GroupInterval = "year" } + }, + GroupSummary = new[] { + new SummaryInfo { Selector = "Item2", SummaryType = "max" } + } + }) + ); + } } } diff --git a/net/DevExtreme.AspNet.Data.Tests/RemoteGroupingTests.cs b/net/DevExtreme.AspNet.Data.Tests/RemoteGroupingTests.cs index 86cbd108..9aac88f5 100644 --- a/net/DevExtreme.AspNet.Data.Tests/RemoteGroupingTests.cs +++ b/net/DevExtreme.AspNet.Data.Tests/RemoteGroupingTests.cs @@ -268,6 +268,27 @@ public void RequireGroupCount_MultiLevels() { Assert.Equal(2, loadResult.groupCount); } + [Fact] + public void RequireGroupCount_Intervals() { + var source = new[] { + new { G1 = new DateTime(2025, 1, 1), PK = 0 }, + new { G1 = new DateTime(2025, 2, 2), PK = 1 }, + new { G1 = new DateTime(2026, 3, 3), PK = 2 } + }; + + var loadOptions = new SampleLoadOptions { + RemoteGrouping = true, + RequireGroupCount = true, + Group = new[] { + new GroupingInfo { Selector = "G1", IsExpanded = false, GroupInterval = "year" }, + }, + Skip = 1 + }; + + var loadResult = DataSourceLoader.Load(source, loadOptions); + Assert.Equal(2, loadResult.groupCount); + } + [Fact] public void Summary_MissingOverload() { // Neither of Min, Max, Sum, Average provides an overload for byte sequences diff --git a/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs b/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs index a21a003d..60957371 100644 --- a/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs +++ b/net/DevExtreme.AspNet.Data/DataSourceExpressionBuilder.cs @@ -33,7 +33,7 @@ public Expression BuildCountExpr() { public Expression BuildLoadGroupsExpr(bool paginate, bool suppressGroups = false, bool suppressTotals = false) { AddFilter(); - AddRemoteGrouping(suppressGroups, suppressTotals); + AddRemoteGrouping(suppressGroups, suppressTotals, suppressGroups); if(paginate) AddPaging(); return Expr; @@ -41,8 +41,15 @@ public Expression BuildLoadGroupsExpr(bool paginate, bool suppressGroups = false public Expression BuildGroupCountExpr() { AddFilter(); - Expr = CreateSelectCompiler().CompileSingle(Expr, Context.Group.Single().Selector); - Expr = QueryableCall(nameof(Queryable.Distinct)); + + var group = Context.Group.Single(); + if(String.IsNullOrEmpty(group.GroupInterval)) { + Expr = CreateSelectCompiler().CompileSingle(Expr, group.Selector); + Expr = QueryableCall(nameof(Queryable.Distinct)); + } else { + AddRemoteGrouping(false, true, true); + } + AddCount(); return Expr; } @@ -75,12 +82,12 @@ void AddPaging() { Expr = QueryableCall(nameof(Queryable.Take), Expression.Constant(Context.Take)); } - void AddRemoteGrouping(bool suppressGroups, bool suppressTotals) { + void AddRemoteGrouping(bool suppressGroups, bool suppressTotals, bool suppressGroupSummary) { var compiler = new RemoteGroupExpressionCompiler( GetItemType(), Context.GuardNulls, Context.ExpandLinqSumType, Context.CreateAnonTypeNewTweaks(), suppressGroups ? null : Context.Group, suppressTotals ? null : Context.TotalSummary, - suppressGroups ? null : Context.GroupSummary + suppressGroupSummary ? null : Context.GroupSummary ); Expr = compiler.Compile(Expr); }