├── .gitignore
├── .travis.yml
├── Kendo.DynamicLinq.Tests
├── Kendo.DynamicLinq.Tests.csproj
├── Properties
│ └── AssemblyInfo.cs
├── SerializationTests.cs
└── packages.config
├── Kendo.DynamicLinq.sln
├── Kendo.DynamicLinq
├── Aggregate.cs
├── DataSourceRequest.cs
├── DataSourceResult.cs
├── Filter.cs
├── Kendo.DynamicLinq.csproj
├── Kendo.DynamicLinq.nuspec
├── Properties
│ └── AssemblyInfo.cs
├── QueryableExtensions.cs
├── Sort.cs
└── packages.config
├── README.md
├── packages
├── NUnit.2.6.3
│ ├── NUnit.2.6.3.nupkg
│ ├── NUnit.2.6.3.nuspec
│ ├── lib
│ │ ├── nunit.framework.dll
│ │ └── nunit.framework.xml
│ └── license.txt
├── System.Linq.Dynamic.1.0.0
│ ├── System.Linq.Dynamic.1.0.0.nupkg
│ ├── System.Linq.Dynamic.1.0.0.nuspec
│ └── lib
│ │ └── net40
│ │ └── System.Linq.Dynamic.dll
└── repositories.config
└── travis.proj
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | ## Ignore Visual Studio temporary files, build results, and
6 | ## files generated by popular Visual Studio add-ons.
7 |
8 | # User-specific files
9 | *.suo
10 | *.user
11 | *.sln.docstates
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Rr]elease/
16 | x64/
17 | *_i.c
18 | *_p.c
19 | *.ilk
20 | *.meta
21 | *.obj
22 | *.pch
23 | *.pdb
24 | *.pgc
25 | *.pgd
26 | *.rsp
27 | *.sbr
28 | *.tlb
29 | *.tli
30 | *.tlh
31 | *.tmp
32 | *.log
33 | *.vspscc
34 | *.vssscc
35 | .builds
36 |
37 | # Publish Web Output
38 | *.Publish.xml
39 |
40 | Kendo.DynamicLinq.*.nupkg
41 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | cache: apt
4 |
5 | install:
6 | - sudo apt-get install mono-devel mono-gmcs nunit-console
7 |
8 | script:
9 | - xbuild travis.proj
10 | - nunit-console ./Kendo.DynamicLinq.Tests/bin/Debug/Kendo.DynamicLinq.Tests.dll
11 |
12 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq.Tests/Kendo.DynamicLinq.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {92FF629E-8872-4CCE-B558-F9FE437DDA86}
8 | Library
9 | Properties
10 | Kendo.DynamicLinq.Tests
11 | Kendo.DynamicLinq.Tests
12 | v4.0
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | {2bd75d53-e0ea-4995-8b0f-60ad709945ac}
59 | Kendo.DynamicLinq
60 |
61 |
62 |
63 |
70 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Kendo.DynamicLinq.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Kendo.DynamicLinq.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("59ff0f3d-edff-45c3-8e15-691d02dcd302")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq.Tests/SerializationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Runtime.Serialization;
5 | using System.Runtime.Serialization.Json;
6 | using System.Text;
7 |
8 | namespace Kendo.DynamicLinq.Tests
9 | {
10 | [KnownType(typeof(Person))]
11 | public class Person
12 | {
13 | public int Age { get; set; }
14 | }
15 |
16 | [TestFixture]
17 | public class SerializationTests
18 | {
19 | [Test]
20 | public void DataContractJsonSerializerSerializesEmptyAggregates()
21 | {
22 | using (var stream = new MemoryStream())
23 | {
24 | var serializer = new DataContractJsonSerializer(typeof(DataSourceResult));
25 |
26 | serializer.WriteObject(stream, new[] { "foo" }.AsQueryable().ToDataSourceResult(1, 0, null, null));
27 |
28 | Assert.AreEqual("{\"Aggregates\":null,\"Data\":[\"foo\"],\"Total\":1}", Encoding.UTF8.GetString(stream.ToArray()));
29 | }
30 | }
31 |
32 | [Test]
33 | public void DataContractJsonSerializerSerializesAggregates()
34 | {
35 | using (var stream = new MemoryStream())
36 | {
37 | var serializer = new DataContractJsonSerializer(typeof(DataSourceResult), new [] { typeof (Person) });
38 |
39 | var people = new[] { new Person { Age = 30 }, new Person { Age = 30 } };
40 |
41 | serializer.WriteObject(stream, people.AsQueryable().ToDataSourceResult(1, 2, null, null, new [] { new Aggregator {
42 | Aggregate = "sum",
43 | Field = "Age"
44 | } }));
45 |
46 | var json = Encoding.UTF8.GetString(stream.ToArray()).Replace("\"__type\":\"DynamicClass2:#\",", "");
47 |
48 | Assert.AreEqual("{\"Aggregates\":{\"Age\":{\"sum\":60}},\"Data\":[],\"Total\":2}", json);
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kendo.DynamicLinq", "Kendo.DynamicLinq\Kendo.DynamicLinq.csproj", "{2BD75D53-E0EA-4995-8B0F-60AD709945AC}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kendo.DynamicLinq.Tests", "Kendo.DynamicLinq.Tests\Kendo.DynamicLinq.Tests.csproj", "{92FF629E-8872-4CCE-B558-F9FE437DDA86}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {2BD75D53-E0EA-4995-8B0F-60AD709945AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {2BD75D53-E0EA-4995-8B0F-60AD709945AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {2BD75D53-E0EA-4995-8B0F-60AD709945AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {2BD75D53-E0EA-4995-8B0F-60AD709945AC}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {92FF629E-8872-4CCE-B558-F9FE437DDA86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {92FF629E-8872-4CCE-B558-F9FE437DDA86}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {92FF629E-8872-4CCE-B558-F9FE437DDA86}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {92FF629E-8872-4CCE-B558-F9FE437DDA86}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Aggregate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Runtime.Serialization;
7 |
8 | namespace Kendo.DynamicLinq
9 | {
10 | ///
11 | /// Represents a aggregate expression of Kendo DataSource.
12 | ///
13 | [DataContract(Name = "aggregate")]
14 | public class Aggregator
15 | {
16 | ///
17 | /// Gets or sets the name of the aggregated field (property).
18 | ///
19 | [DataMember(Name = "field")]
20 | public string Field { get; set; }
21 |
22 | ///
23 | /// Gets or sets the aggregate.
24 | ///
25 | [DataMember(Name = "aggregate")]
26 | public string Aggregate { get; set; }
27 |
28 | ///
29 | /// Get MethodInfo.
30 | ///
31 | /// Specifies the type of querable data.
32 | /// A MethodInfo for field.
33 | public MethodInfo MethodInfo(Type type)
34 | {
35 | var proptype = type.GetProperty(Field).PropertyType;
36 | switch (Aggregate)
37 | {
38 | case "max":
39 | case "min":
40 | return GetMethod(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(Aggregate), MinMaxFunc().Method, 2).MakeGenericMethod(type, proptype);
41 | case "average":
42 | case "sum":
43 | return GetMethod(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(Aggregate),
44 | ((Func)this.GetType().GetMethod("SumAvgFunc", BindingFlags.Static | BindingFlags.NonPublic)
45 | .MakeGenericMethod(proptype).Invoke(null, null)).Method, 1).MakeGenericMethod(type);
46 | case "count":
47 | return GetMethod(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(Aggregate),
48 | Nullable.GetUnderlyingType(proptype) != null ? CountNullableFunc().Method : CountFunc().Method, 1).MakeGenericMethod(type);
49 | }
50 | return null;
51 | }
52 |
53 | private static MethodInfo GetMethod(string methodName, MethodInfo methodTypes, int genericArgumentsCount)
54 | {
55 | var methods = from method in typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static)
56 | let parameters = method.GetParameters()
57 | let genericArguments = method.GetGenericArguments()
58 | where method.Name == methodName &&
59 | genericArguments.Length == genericArgumentsCount &&
60 | parameters.Select(p => p.ParameterType).SequenceEqual((Type[])methodTypes.Invoke(null, genericArguments))
61 | select method;
62 | return methods.FirstOrDefault();
63 | }
64 |
65 | private static Func CountNullableFunc()
66 | {
67 | return (T) => new[]
68 | {
69 | typeof(IQueryable<>).MakeGenericType(T),
70 | typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(T, typeof(bool)))
71 | };
72 | }
73 |
74 | private static Func CountFunc()
75 | {
76 | return (T) => new[]
77 | {
78 | typeof(IQueryable<>).MakeGenericType(T)
79 | };
80 | }
81 |
82 | private static Func MinMaxFunc()
83 | {
84 | return (T, U) => new[]
85 | {
86 | typeof (IQueryable<>).MakeGenericType(T),
87 | typeof (Expression<>).MakeGenericType(typeof (Func<,>).MakeGenericType(T, U))
88 | };
89 | }
90 |
91 | private static Func SumAvgFunc()
92 | {
93 | return (T) => new[]
94 | {
95 | typeof (IQueryable<>).MakeGenericType(T),
96 | typeof (Expression<>).MakeGenericType(typeof (Func<,>).MakeGenericType(T, typeof(U)))
97 | };
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/DataSourceRequest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Kendo.DynamicLinq
4 | {
5 | ///
6 | /// Describes a Kendo Datasource request.
7 | ///
8 | public class DataSourceRequest
9 | {
10 | ///
11 | /// Specifies how many items to take.
12 | ///
13 | public int Take { get; set; }
14 |
15 | ///
16 | /// Specifies how many items to skip.
17 | ///
18 | public int Skip { get; set; }
19 |
20 | ///
21 | /// Specifies the requested sort order.
22 | ///
23 | public IEnumerable Sort { get; set; }
24 |
25 | ///
26 | /// Specifies the requested filter.
27 | ///
28 | public Filter Filter { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/DataSourceResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Runtime.Serialization;
6 |
7 | namespace Kendo.DynamicLinq
8 | {
9 | ///
10 | /// Describes the result of Kendo DataSource read operation.
11 | ///
12 | [KnownType("GetKnownTypes")]
13 | public class DataSourceResult
14 | {
15 | ///
16 | /// Represents a single page of processed data.
17 | ///
18 | public IEnumerable Data { get; set; }
19 |
20 | ///
21 | /// The total number of records available.
22 | ///
23 | public int Total { get; set; }
24 |
25 | ///
26 | /// Represents a requested aggregates.
27 | ///
28 | public object Aggregates { get; set; }
29 |
30 | ///
31 | /// Used by the KnownType attribute which is required for WCF serialization support
32 | ///
33 | ///
34 | private static Type[] GetKnownTypes()
35 | {
36 | var assembly = AppDomain.CurrentDomain
37 | .GetAssemblies()
38 | .FirstOrDefault(a => a.FullName.StartsWith("DynamicClasses"));
39 |
40 | if (assembly == null)
41 | {
42 | return new Type[0];
43 | }
44 |
45 | return assembly.GetTypes()
46 | .Where(t => t.Name.StartsWith("DynamicClass"))
47 | .ToArray();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Filter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections.Generic;
4 | using System.Runtime.Serialization;
5 |
6 | namespace Kendo.DynamicLinq
7 | {
8 | ///
9 | /// Represents a filter expression of Kendo DataSource.
10 | ///
11 | [DataContract]
12 | public class Filter
13 | {
14 | ///
15 | /// Gets or sets the name of the sorted field (property). Set to null if the Filters property is set.
16 | ///
17 | [DataMember(Name = "field")]
18 | public string Field { get; set; }
19 |
20 | ///
21 | /// Gets or sets the filtering operator. Set to null if the Filters property is set.
22 | ///
23 | [DataMember(Name = "operator")]
24 | public string Operator { get; set; }
25 |
26 | ///
27 | /// Gets or sets the filtering value. Set to null if the Filters property is set.
28 | ///
29 | [DataMember(Name = "value")]
30 | public object Value { get; set; }
31 |
32 | ///
33 | /// Gets or sets the filtering logic. Can be set to "or" or "and". Set to null unless Filters is set.
34 | ///
35 | [DataMember(Name = "logic")]
36 | public string Logic { get; set; }
37 |
38 | ///
39 | /// Gets or sets the child filter expressions. Set to null if there are no child expressions.
40 | ///
41 | [DataMember(Name = "filters")]
42 | public IEnumerable Filters { get; set; }
43 |
44 | ///
45 | /// Mapping of Kendo DataSource filtering operators to Dynamic Linq
46 | ///
47 | private static readonly IDictionary operators = new Dictionary
48 | {
49 | {"eq", "="},
50 | {"neq", "!="},
51 | {"lt", "<"},
52 | {"lte", "<="},
53 | {"gt", ">"},
54 | {"gte", ">="},
55 | {"startswith", "StartsWith"},
56 | {"endswith", "EndsWith"},
57 | {"contains", "Contains"},
58 | {"doesnotcontain", "Contains"}
59 | };
60 |
61 | ///
62 | /// Get a flattened list of all child filter expressions.
63 | ///
64 | public IList All()
65 | {
66 | var filters = new List();
67 |
68 | Collect(filters);
69 |
70 | return filters;
71 | }
72 |
73 | private void Collect(IList filters)
74 | {
75 | if (Filters != null && Filters.Any())
76 | {
77 | foreach (Filter filter in Filters)
78 | {
79 | filters.Add(filter);
80 |
81 | filter.Collect(filters);
82 | }
83 | }
84 | else
85 | {
86 | filters.Add(this);
87 | }
88 | }
89 |
90 | ///
91 | /// Converts the filter expression to a predicate suitable for Dynamic Linq e.g. "Field1 = @1 and Field2.Contains(@2)"
92 | ///
93 | /// A list of flattened filters.
94 | public string ToExpression(IList filters)
95 | {
96 | if (Filters != null && Filters.Any())
97 | {
98 | return "(" + String.Join(" " + Logic + " ", Filters.Select(filter => filter.ToExpression(filters)).ToArray()) + ")";
99 | }
100 |
101 | int index = filters.IndexOf(this);
102 |
103 | string comparison = operators[Operator];
104 |
105 | if (Operator == "doesnotcontain")
106 | {
107 | return String.Format("!{0}.{1}(@{2})", Field, comparison, index);
108 | }
109 |
110 | if (comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains")
111 | {
112 | return String.Format("{0}.{1}(@{2})", Field, comparison, index);
113 | }
114 |
115 | return String.Format("{0} {1} @{2}", Field, comparison, index);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Kendo.DynamicLinq.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Release
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {2BD75D53-E0EA-4995-8B0F-60AD709945AC}
9 | Library
10 | Properties
11 | Kendo.DynamicLinq
12 | Kendo.DynamicLinq
13 | v4.0
14 | 512
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | ..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Kendo.DynamicLinq.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | Atanas Korchev
8 | https://github.com/kendo-labs/dlinq-helpers
9 | false
10 | $description$
11 | Copyright 2013
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Kendo.DynamicLinq")]
8 | [assembly: AssemblyDescription("Server side paging, sorting and filtering via Dynamic Linq")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyProduct("Kendo.DynamicLinq")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | // Setting ComVisible to false makes the types in this assembly not visible
15 | // to COM components. If you need to access a type in this assembly from
16 | // COM, set the ComVisible attribute to true on that type.
17 | [assembly: ComVisible(false)]
18 |
19 | // The following GUID is for the ID of the typelib if this project is exposed to COM
20 | [assembly: Guid("969930e8-6f3d-4369-bdc1-835628cd125f")]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Build and Revision Numbers
30 | // by using the '*' as shown below:
31 | // [assembly: AssemblyVersion("1.0.*")]
32 | [assembly: AssemblyVersion("1.1.2.0")]
33 | [assembly: AssemblyFileVersion("1.1.2.0")]
34 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/QueryableExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Dynamic;
5 | using System.Linq.Expressions;
6 | using DynamicExpression = System.Linq.Dynamic.DynamicExpression;
7 |
8 | namespace Kendo.DynamicLinq
9 | {
10 | public static class QueryableExtensions
11 | {
12 | ///
13 | /// Applies data processing (paging, sorting, filtering and aggregates) over IQueryable using Dynamic Linq.
14 | ///
15 | /// The type of the IQueryable.
16 | /// The IQueryable which should be processed.
17 | /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource.
18 | /// Specifies how many items to skip.
19 | /// Specifies the current sort order.
20 | /// Specifies the current filter.
21 | /// Specifies the current aggregates.
22 | /// A DataSourceResult object populated from the processed IQueryable.
23 | public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, IEnumerable sort, Filter filter, IEnumerable aggregates)
24 | {
25 | // Filter the data first
26 | queryable = Filter(queryable, filter);
27 |
28 | // Calculate the total number of records (needed for paging)
29 | var total = queryable.Count();
30 |
31 | // Calculate the aggregates
32 | var aggregate = Aggregate(queryable, aggregates);
33 |
34 | // Sort the data
35 | queryable = Sort(queryable, sort);
36 |
37 | // Finally page the data
38 | if (take > 0)
39 | {
40 | queryable = Page(queryable, take, skip);
41 | }
42 |
43 | return new DataSourceResult
44 | {
45 | Data = queryable.ToList(),
46 | Total = total,
47 | Aggregates = aggregate
48 | };
49 | }
50 |
51 | ///
52 | /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq.
53 | ///
54 | /// The type of the IQueryable.
55 | /// The IQueryable which should be processed.
56 | /// Specifies how many items to take. Configurable via the pageSize setting of the Kendo DataSource.
57 | /// Specifies how many items to skip.
58 | /// Specifies the current sort order.
59 | /// Specifies the current filter.
60 | /// A DataSourceResult object populated from the processed IQueryable.
61 | public static DataSourceResult ToDataSourceResult(this IQueryable queryable, int take, int skip, IEnumerable sort, Filter filter)
62 | {
63 | return queryable.ToDataSourceResult(take, skip, sort, filter, null);
64 | }
65 |
66 | ///
67 | /// Applies data processing (paging, sorting and filtering) over IQueryable using Dynamic Linq.
68 | ///
69 | /// The type of the IQueryable.
70 | /// The IQueryable which should be processed.
71 | /// The DataSourceRequest object containing take, skip, order, and filter data.
72 | /// A DataSourceResult object populated from the processed IQueryable.
73 | public static DataSourceResult ToDataSourceResult(this IQueryable queryable, DataSourceRequest request)
74 | {
75 | return queryable.ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter, null);
76 | }
77 |
78 | private static IQueryable Filter(IQueryable queryable, Filter filter)
79 | {
80 | if (filter != null && filter.Logic != null)
81 | {
82 | // Collect a flat list of all filters
83 | var filters = filter.All();
84 |
85 | // Get all filter values as array (needed by the Where method of Dynamic Linq)
86 | var values = filters.Select(f => f.Value).ToArray();
87 |
88 | // Create a predicate expression e.g. Field1 = @0 And Field2 > @1
89 | string predicate = filter.ToExpression(filters);
90 |
91 | // Use the Where method of Dynamic Linq to filter the data
92 | queryable = queryable.Where(predicate, values);
93 | }
94 |
95 | return queryable;
96 | }
97 |
98 | private static object Aggregate(IQueryable queryable, IEnumerable aggregates)
99 | {
100 | if (aggregates != null && aggregates.Any())
101 | {
102 | var objProps = new Dictionary();
103 | var groups = aggregates.GroupBy(g => g.Field);
104 | Type type = null;
105 | foreach (var group in groups)
106 | {
107 | var fieldProps = new Dictionary();
108 | foreach (var aggregate in group)
109 | {
110 | var prop = typeof (T).GetProperty(aggregate.Field);
111 | var param = Expression.Parameter(typeof (T), "s");
112 | var selector = aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) != null)
113 | ? Expression.Lambda(Expression.NotEqual(Expression.MakeMemberAccess(param, prop), Expression.Constant(null, prop.PropertyType)), param)
114 | : Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
115 | var mi = aggregate.MethodInfo(typeof (T));
116 | if (mi == null)
117 | continue;
118 |
119 | var val = queryable.Provider.Execute(Expression.Call(null, mi,
120 | aggregate.Aggregate == "count" && (Nullable.GetUnderlyingType(prop.PropertyType) == null)
121 | ? new[] { queryable.Expression }
122 | : new[] { queryable.Expression, Expression.Quote(selector) }));
123 |
124 | fieldProps.Add(new DynamicProperty(aggregate.Aggregate, typeof(object)), val);
125 | }
126 | type = DynamicExpression.CreateClass(fieldProps.Keys);
127 | var fieldObj = Activator.CreateInstance(type);
128 | foreach (var p in fieldProps.Keys)
129 | type.GetProperty(p.Name).SetValue(fieldObj, fieldProps[p], null);
130 | objProps.Add(new DynamicProperty(group.Key, fieldObj.GetType()), fieldObj);
131 | }
132 |
133 | type = DynamicExpression.CreateClass(objProps.Keys);
134 |
135 | var obj = Activator.CreateInstance(type);
136 |
137 | foreach (var p in objProps.Keys)
138 | {
139 | type.GetProperty(p.Name).SetValue(obj, objProps[p], null);
140 | }
141 |
142 | return obj;
143 | }
144 | else
145 | {
146 | return null;
147 | }
148 | }
149 |
150 | private static IQueryable Sort(IQueryable queryable, IEnumerable sort)
151 | {
152 | if (sort != null && sort.Any())
153 | {
154 | // Create ordering expression e.g. Field1 asc, Field2 desc
155 | var ordering = String.Join(",", sort.Select(s => s.ToExpression()));
156 |
157 | // Use the OrderBy method of Dynamic Linq to sort the data
158 | return queryable.OrderBy(ordering);
159 | }
160 |
161 | return queryable;
162 | }
163 |
164 | private static IQueryable Page(IQueryable queryable, int take, int skip)
165 | {
166 | return queryable.Skip(skip).Take(take);
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/Sort.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Runtime.Serialization;
4 |
5 | namespace Kendo.DynamicLinq
6 | {
7 | ///
8 | /// Represents a sort expression of Kendo DataSource.
9 | ///
10 | [DataContract]
11 | public class Sort
12 | {
13 | ///
14 | /// Gets or sets the name of the sorted field (property).
15 | ///
16 | [DataMember(Name = "field")]
17 | public string Field { get; set; }
18 |
19 | ///
20 | /// Gets or sets the sort direction. Should be either "asc" or "desc".
21 | ///
22 | [DataMember(Name = "dir")]
23 | public string Dir { get; set; }
24 |
25 | ///
26 | /// Converts to form required by Dynamic Linq e.g. "Field1 desc"
27 | ///
28 | public string ToExpression()
29 | {
30 | return Field + " " + Dir;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Kendo.DynamicLinq/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Kendo.DynamicLinq
2 |
3 | [](https://travis-ci.org/kendo-labs/dlinq-helpers)
4 |
5 | # Note
6 | Kendo UI Labs projects are experimental and largely built and supported by the community. As such Telerik does not provide official support for any of the Kendo UI Labs projects via Telerik support agreements. We do encourage you to open an issue or visit [Stack Overflow](http://www.stackoverflow.com).
7 |
8 | ## Description
9 | Kendo.DynamicLinq implements server paging, filtering, sorting and aggregating via Dynamic Linq.
10 |
11 |
12 | ## Usage
13 | 1. Add the Kendo.DynamicLinq NuGet package to your project.
14 | 1. Configure your Kendo DataSource to send its options as JSON.
15 |
16 | parameterMap: function(options, type) {
17 | return JSON.stringify(options);
18 | }
19 | 1. Configure the `schema` of the DataSource.
20 |
21 | schema: {
22 | data: "Data",
23 | total: "Total",
24 | aggregates: "Aggregates"
25 |
26 | }
27 | 1. Import the Kendo.DynamicLinq namespace.
28 | 1. Use the `ToDataSourceResult` extension method to apply paging, sorting and filtering.
29 |
30 | [WebMethod]
31 | public static DataSourceResult Products(int take, int skip, IEnumerable sort, Filter filter, IEnumerable aggregates)
32 | {
33 | using (var northwind = new Northwind())
34 | {
35 | return northwind.Products
36 | .OrderBy(p => p.ProductID) // EF requires ordering for paging
37 | // Use a view model to avoid serializing internal Entity Framework properties as JSON
38 | .Select(p => new ProductViewModel
39 | {
40 | ProductID = p.ProductID,
41 | ProductName = p.ProductName,
42 | UnitPrice = p.UnitPrice,
43 | UnitsInStock = p.UnitsInStock,
44 | Discontinued = p.Discontinued
45 | })
46 | .ToDataSourceResult(take, skip, sort, filter, aggregates);
47 | }
48 | }
49 |
50 | ## Examples
51 |
52 | The following examples use Kendo.DynamicLinq.
53 |
54 | - [ASP.NET MVC](https://github.com/telerik/kendo-examples-asp-net-mvc/tree/master/grid-crud)
55 | - [ASP.NET Web Forms and Page Methods](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-page-methods-crud)
56 | - [ASP.NET Web Forms and WCF](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-wcf-crud)
57 | - [ASP.NET Web Forms and Web Services](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-web-service-crud)
58 | - [ASP.NET Web Forms and Web API](https://github.com/telerik/kendo-examples-asp-net/tree/master/grid-webapi-crud)
59 |
--------------------------------------------------------------------------------
/packages/NUnit.2.6.3/NUnit.2.6.3.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kendo-labs/dlinq-helpers/459b11d3eded4cef215b51f5b1628be1bbfacd7e/packages/NUnit.2.6.3/NUnit.2.6.3.nupkg
--------------------------------------------------------------------------------
/packages/NUnit.2.6.3/NUnit.2.6.3.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NUnit
5 | 2.6.3
6 | NUnit
7 | Charlie Poole
8 | Charlie Poole
9 | http://nunit.org/nuget/license.html
10 | http://nunit.org/
11 | http://nunit.org/nuget/nunit_32x32.png
12 | false
13 | NUnit features a fluent assert syntax, parameterized, generic and theory tests and is user-extensible. A number of runners, both from the NUnit project and by third parties, are able to execute NUnit tests.
14 |
15 | Version 2.6 is the seventh major release of this well-known and well-tested programming tool.
16 |
17 | This package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner.
18 | NUnit is a unit-testing framework for all .Net languages with a strong TDD focus.
19 | Version 2.6 is the seventh major release of NUnit.
20 |
21 | Unlike earlier versions, this package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner.
22 |
23 | The nunit.mocks assembly is now provided by the NUnit.Mocks package. The pnunit.framework assembly is provided by the pNUnit package.
24 | en-US
25 | nunit test testing tdd framework fluent assert theory plugin addin
26 |
27 |
--------------------------------------------------------------------------------
/packages/NUnit.2.6.3/lib/nunit.framework.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kendo-labs/dlinq-helpers/459b11d3eded4cef215b51f5b1628be1bbfacd7e/packages/NUnit.2.6.3/lib/nunit.framework.dll
--------------------------------------------------------------------------------
/packages/NUnit.2.6.3/license.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kendo-labs/dlinq-helpers/459b11d3eded4cef215b51f5b1628be1bbfacd7e/packages/NUnit.2.6.3/license.txt
--------------------------------------------------------------------------------
/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kendo-labs/dlinq-helpers/459b11d3eded4cef215b51f5b1628be1bbfacd7e/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nupkg
--------------------------------------------------------------------------------
/packages/System.Linq.Dynamic.1.0.0/System.Linq.Dynamic.1.0.0.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | System.Linq.Dynamic
5 | 1.0.0
6 | Microsoft
7 | Microsoft
8 | http://www.opensource.org/licenses/ms-pl
9 | https://github.com/kahanu/System.Linq.Dynamic
10 | false
11 | This is the Microsoft assembly for the .Net 4.0 Dynamic language functionality.
12 | system linq dynamic
13 |
14 |
--------------------------------------------------------------------------------
/packages/System.Linq.Dynamic.1.0.0/lib/net40/System.Linq.Dynamic.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kendo-labs/dlinq-helpers/459b11d3eded4cef215b51f5b1628be1bbfacd7e/packages/System.Linq.Dynamic.1.0.0/lib/net40/System.Linq.Dynamic.dll
--------------------------------------------------------------------------------
/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/travis.proj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------