Skip to content

Commit 48787be

Browse files
author
JftCoCo
committed
1. Change the property "Group" of DataSourceResult to "Groups".
2. Add new property "Aggregate" to DataSourceRequest. 3. Fixed getting wrong grouping data in the request using aggregates in grouping configuration.
1 parent c9aaee6 commit 48787be

12 files changed

Lines changed: 158 additions & 59 deletions

.vscode/launch.json

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"version": "0.2.0",
66
"configurations": [
77
{
8-
"name": ".NET Core Launch (console)",
8+
"name": ".NET Core Launch 1.0(console)",
99
"type": "coreclr",
1010
"request": "launch",
1111
"preLaunchTask": "build",
@@ -16,7 +16,33 @@
1616
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
1717
"console": "internalConsole",
1818
"stopAtEntry": false,
19-
"internalConsoleOptions": "openOnSessionStart"
19+
"internalConsoleOptions": "openOnSessionStart",
20+
"logging": {
21+
"engineLogging": false,
22+
"moduleLoad": false,
23+
"exceptions": true,
24+
"browserStdOut": false
25+
}
26+
},
27+
{
28+
"name": ".NET Core Launch 2.0(console)",
29+
"type": "coreclr",
30+
"request": "launch",
31+
"preLaunchTask": "build",
32+
// If you have changed target frameworks, make sure to update the program path.
33+
"program": "${workspaceFolder}/src/Kendo.DynamicLinqCore.Test/bin/Debug/netcoreapp2.1/Kendo.DynamicLinqCore.Test.dll",
34+
"args": [],
35+
"cwd": "${workspaceFolder}/src/Kendo.DynamicLinqCore.Test",
36+
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
37+
"console": "internalConsole",
38+
"stopAtEntry": false,
39+
"internalConsoleOptions": "openOnSessionStart",
40+
"logging": {
41+
"engineLogging": false,
42+
"moduleLoad": false,
43+
"exceptions": true,
44+
"browserStdOut": false
45+
}
2046
},
2147
{
2248
"name": ".NET Core Attach",

README.md

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Downloads](https://img.shields.io/nuget/dt/Kendo.DynamicLinqCore.svg)](https://www.nuget.org/packages/Kendo.DynamicLinqCore)
55

66
## Description
7-
Kendo.DynamicLinqCore implements server paging, filtering, sorting and aggregating to Kendo UI via Dynamic Linq for .Net Core App(1.x ~ 2.x).
7+
Kendo.DynamicLinqCore implements server paging, filtering, sorting, grouping and aggregating to Kendo UI via Dynamic Linq for .Net Core App(1.x ~ 2.x).
88

99
## Usage
1010
1. Add the Kendo.DynamicLinqCore NuGet package to your project.
@@ -22,7 +22,7 @@ schema: {
2222
data: "Data",
2323
total: "Total",
2424
aggregates: "Aggregates",
25-
groups: "Group",
25+
groups: "Groups",
2626
errors: "Errors"
2727
}
2828
```
@@ -37,7 +37,7 @@ dataSource: {
3737
data: "Data",
3838
total: "Total",
3939
aggregates: "Aggregates",
40-
groups: "Group",
40+
groups: "Groups",
4141
errors: "Errors",
4242
...
4343
},
@@ -72,12 +72,12 @@ dataSource: {
7272
..... Other kendo grid code .....
7373
```
7474
5. Import the Kendo.DynamicLinqCore namespace.
75-
6. Use the `ToDataSourceResult` extension method to apply paging, sorting and filtering
75+
6. Use the `ToDataSourceResult` extension method to apply paging, sorting, filtering, grouping and aggregating.
7676
```c#
7777
using Kendo.DynamicLinqCore
7878

7979
[WebMethod]
80-
public static DataSourceResult Products(int take, int skip, IEnumerable<Sort> sort, Filter filter, IEnumerable<Aggregator> aggregates, IEnumerable<Sort> group)
80+
public static DataSourceResult Products(int take, int skip, IEnumerable<Sort> sort, Filter filter, IEnumerable<Aggregator> aggregates, IEnumerable<Group> groups)
8181
{
8282
using (var northwind = new Northwind())
8383
{
@@ -91,7 +91,7 @@ public static DataSourceResult Products(int take, int skip, IEnumerable<Sort> so
9191
UnitsInStock = p.UnitsInStock,
9292
Discontinued = p.Discontinued
9393
})
94-
.ToDataSourceResult(take, skip, sort, filter, aggregates, group);
94+
.ToDataSourceResult(take, skip, sort, filter, aggregates, groups);
9595
}
9696
}
9797
```
@@ -114,7 +114,7 @@ public IActionResult Products([FromBody] DataSourceRequest requestModel)
114114
UnitsInStock = p.UnitsInStock,
115115
Discontinued = p.Discontinued
116116
})
117-
.ToDataSourceResult(requestModel.Take, requestModel.Skip, requestModel.Sort, requestModel.Filter);
117+
.ToDataSourceResult(requestModel.Take, requestModel.Skip, requestModel.Sort, requestModel.Filter, requestModel.Aggregate, requestModel.Group);
118118
}
119119
}
120120
```
@@ -143,17 +143,14 @@ public class MyContext : DbContext
143143
4. Run "dotnet pack --configuration Release"
144144

145145
## Note
146-
Kendo.DynamicLinqCore is referred to Kendo.DynamicLinq by [kendo-labs](https://github.com/kendo-labs/dlinq-helpers). Related notes can refer it.
146+
Kendo.DynamicLinqCore is referred to Kendo.DynamicLinq by [Ali Sarkis](https://github.com/mshtawythug/dlinq-helpers).
147147

148-
## Examples
149-
The following examples use Kendo.DynamicLinq(Not Kendo.DynamicLinqCore, but similar) and you can consult.
148+
## Kendo UI Documentation
149+
The following links are Kendo UI online docs(related to this package) and you can refer to.
150150

151-
- [ASP.NET MVC](https://github.com/telerik/kendo-examples-asp-net-mvc/tree/master/grid-crud)
152-
- [ASP.NET Web Forms and Page Methods](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-page-methods-crud)
153-
- [ASP.NET Web Forms and WCF](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-wcf-crud)
154-
- [ASP.NET Web Forms and Web Services](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-web-service-crud)
155-
- [ASP.NET Web Forms and Web API](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-webapi-crud)
151+
- [Kendo UI Grid](https://docs.telerik.com/kendo-ui/api/javascript/ui/grid)
152+
- [Kendo DataSource](https://docs.telerik.com/kendo-ui/api/javascript/data/datasource)
156153

157-
More Kendo UI Grid configuration can refer to [here](https://demos.telerik.com/kendo-ui/)
154+
More Kendo UI configuration can refer to [here](https://demos.telerik.com/kendo-ui/)
158155

159156

src/Kendo.DynamicLinqCore.Test/Kendo.DynamicLinqCore.Test.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp1.0</TargetFramework>
5+
<TargetFrameworks>netcoreapp1.0;netcoreapp2.1</TargetFrameworks>
66
</PropertyGroup>
77

8+
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp1.0'"></ItemGroup>
9+
10+
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp2.1'"></ItemGroup>
11+
812
<ItemGroup>
913
<ProjectReference Include="../Kendo.DynamicLinqCore/Kendo.DynamicLinqCore.csproj" />
1014
</ItemGroup>

src/Kendo.DynamicLinqCore.Test/Program.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,70 @@ class Program
1212
Identification = Guid.Parse("F057D609-F1F3-4E5C-BC09-0AC0BBE1007D"),
1313
Name = "Monie",
1414
Introduce = "I'm Monie",
15-
Salary = 1000000,
15+
Salary = 1000,
1616
EmployeeNumber = 10,
1717
Birthday = new DateTime(2000,5,5)
1818
},
1919
new Person {
2020
Identification = Guid.Parse("F586A608-4095-4E8E-8F21-AEFC0DFDB61F"),
2121
Name = "CoCo",
2222
Introduce = "I'm CoCo",
23-
Salary = 2500000,
23+
Salary = 2500,
2424
EmployeeNumber = 77,
2525
Birthday = new DateTime(1986,10,10)
2626
},
2727
new Person {
2828
Identification = Guid.Parse("F4FFE20C-4DE5-4DC5-9686-955FB74EE05E"),
2929
Name = "Kirin",
30-
Salary = 3000000,
30+
Salary = 3000,
3131
EmployeeNumber = 66,
3232
Birthday = new DateTime(1984,7,8)
3333
},
3434
new Person {
3535
Identification = Guid.Parse("CCAB16DB-070B-4A93-846A-81AEEFDD42EE"),
3636
Name = "Rock",
3737
Introduce = "",
38-
Salary = 1750000,
38+
Salary = 1750,
3939
EmployeeNumber = 35,
4040
Birthday = new DateTime(1976,11,6)
4141
},
4242
new Person {
4343
Identification = null,
4444
Name = "Pikachu",
4545
Introduce = "Pika~ Pika~",
46-
Salary = 66000,
46+
Salary = 6600,
4747
EmployeeNumber = 18,
4848
Birthday = new DateTime(2005,3,16)
4949
}
5050
};
5151

5252
static void Main(string[] args)
53-
{
53+
{
54+
#if NETCOREAPP1_0 || NETCOREAPP1_1
55+
Console.WriteLine("/---------- Net Core App 1.x ----------/");
56+
#else
57+
Console.WriteLine("/---------- Net Core App 2.x ----------/");
58+
#endif
59+
60+
Console.WriteLine("----------------------------------------");
61+
5462
/* Test 1 */
5563
var result = people.AsQueryable().ToDataSourceResult(1, 2, null, null, new[]
5664
{
5765
new Aggregator
5866
{
5967
Aggregate = "sum",
6068
Field = "Salary"
69+
},
70+
new Aggregator
71+
{
72+
Aggregate = "average",
73+
Field = "Salary"
6174
}
6275
}, null);
6376

64-
Console.WriteLine("/********** Test 1 **********/");
65-
Console.WriteLine(result.Aggregates);
77+
Console.WriteLine("\r\n/********** Test 1 **********/");
78+
Console.WriteLine(result.Aggregates); // { Salary = { sum = 14850, average = 2970 } }
6679

6780

6881
/* Test 2 */
@@ -79,10 +92,10 @@ static void Main(string[] args)
7992
Logic = "and"
8093
}, null, null);
8194

82-
Console.WriteLine("/********** Test 2 **********/");
95+
Console.WriteLine("\r\n/********** Test 2 **********/");
8396
foreach (var p in result.Data)
8497
{
85-
Console.WriteLine((p as Person).Name);
98+
Console.WriteLine((p as Person).Name); // Kirin, Rock
8699
}
87100

88101

@@ -115,10 +128,10 @@ static void Main(string[] args)
115128
Logic = "and"
116129
}, null, null);
117130

118-
Console.WriteLine("/********** Test 3 **********/");
131+
Console.WriteLine("\r\n/********** Test 3 **********/");
119132
foreach (var p in result.Data)
120133
{
121-
Console.WriteLine((p as Person).Name);
134+
Console.WriteLine((p as Person).Name); // CoCo, Monie
122135
}
123136

124137
Console.ReadKey();

src/Kendo.DynamicLinqCore/Aggregator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Globalization;
32
using System.Linq;
43
using System.Linq.Expressions;
54
using System.Reflection;

src/Kendo.DynamicLinqCore/DataSourceRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,10 @@ public class DataSourceRequest
2828
/// Specifies the requested grouping .
2929
/// </summary>
3030
public IEnumerable<Group> Group { get; set; }
31+
32+
/// <summary>
33+
/// Specifies the requested aggregators.
34+
/// </summary>
35+
public IEnumerable<Aggregator> Aggregate { get; set; }
3136
}
3237
}

src/Kendo.DynamicLinqCore/DataSourceResult.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ public class DataSourceResult
2020
/// <summary>
2121
/// Represents a single page of processed grouped data.
2222
/// </summary>
23-
public IEnumerable Group { get; set; }
23+
public IEnumerable Groups { get; set; }
2424

2525
/// <summary>
26-
/// The total number of records available.
26+
/// Represents a requested aggregates.
2727
/// </summary>
28-
public int Total { get; set; }
28+
public object Aggregates { get; set; }
2929

3030
/// <summary>
31-
/// Represents a requested aggregates.
31+
/// The total number of records available.
3232
/// </summary>
33-
public object Aggregates { get; set; }
33+
public int Total { get; set; }
3434

3535
/// <summary>
3636
/// Represents error information from server-side.

src/Kendo.DynamicLinqCore/EnumerableExtensions.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Linq.Dynamic.Core;
5+
using System.Linq.Expressions;
6+
using System.Reflection;
57

68
namespace Kendo.DynamicLinqCore
79
{
@@ -14,7 +16,9 @@ public static dynamic GroupByMany<TElement>(this IEnumerable<TElement> elements,
1416
foreach (var selector in groupSelectors)
1517
{
1618
//compile the Dynamic Expression Lambda for each one
19+
//var expression = DynamicExpressionParser.ParseLambda(typeof(TElement), typeof(object), selector.Field);
1720
var expression = DynamicExpressionParser.ParseLambda(false, typeof(TElement), typeof(object), selector.Field);
21+
1822
//add it to the list
1923
selectors.Add(new GroupSelector<TElement>
2024
{
@@ -41,7 +45,7 @@ public static dynamic GroupByMany<TElement>(this IEnumerable<TElement> elements,
4145
g => new GroupResult
4246
{
4347
Value = g.Key,
44-
Aggregates = selector.Aggregates,
48+
Aggregates = Aggregates(g.AsQueryable(),selector.Aggregates),
4549
HasSubgroups = groupSelectors.Length > 1,
4650
Count = g.Count(),
4751
Items = g.GroupByMany(nextSelectors), //recursivly group the next selectors
@@ -52,6 +56,57 @@ public static dynamic GroupByMany<TElement>(this IEnumerable<TElement> elements,
5256
//if there are not more group selectors return data
5357
return elements;
5458
}
59+
60+
private static object Aggregates<T>(IQueryable<T> queryable, IEnumerable<Aggregator> aggregates)
61+
{
62+
if (aggregates != null && aggregates.Any())
63+
{
64+
var objProps = new Dictionary<DynamicProperty, object>();
65+
var groups = aggregates.GroupBy(g => g.Field);
66+
Type type = null;
67+
68+
foreach (var group in groups)
69+
{
70+
var fieldProps = new Dictionary<DynamicProperty, object>();
71+
foreach (var aggregate in group)
72+
{
73+
var prop = typeof(T).GetProperty(aggregate.Field);
74+
var param = Expression.Parameter(typeof(T), "s");
75+
var selector = aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) != null)
76+
? Expression.Lambda(Expression.NotEqual(Expression.MakeMemberAccess(param, prop), Expression.Constant(null, prop.PropertyType)), param)
77+
: Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
78+
var mi = aggregate.MethodInfo(typeof(T));
79+
if (mi == null) continue;
80+
81+
var val = queryable.Provider.Execute(Expression.Call(null, mi, aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) == null)
82+
? new[] { queryable.Expression }
83+
: new[] { queryable.Expression, Expression.Quote(selector) }));
84+
85+
fieldProps.Add(new DynamicProperty(aggregate.Aggregate, typeof(object)), val);
86+
}
87+
88+
type = DynamicClassFactory.CreateType(fieldProps.Keys.ToList());
89+
var fieldObj = Activator.CreateInstance(type);
90+
foreach (var p in fieldProps.Keys)
91+
{
92+
type.GetProperty(p.Name).SetValue(fieldObj, fieldProps[p], null);
93+
}
94+
objProps.Add(new DynamicProperty(group.Key, fieldObj.GetType()), fieldObj);
95+
}
96+
97+
type = DynamicClassFactory.CreateType(objProps.Keys.ToList());
98+
99+
var obj = Activator.CreateInstance(type);
100+
foreach (var p in objProps.Keys)
101+
{
102+
type.GetProperty(p.Name).SetValue(obj, objProps[p], null);
103+
}
104+
105+
return obj;
106+
}
107+
108+
return null;
109+
}
55110

56111
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
57112
{

0 commit comments

Comments
 (0)