From 9dd5d59b855ad7d5c4badb5d3acb0b0194b349f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leb=C3=A9e?= Date: Mon, 12 Mar 2018 18:00:02 -0500 Subject: [PATCH] supporting equality comparer :) --- PoweredSoft.DynamicLinq.Test/GroupingTests.cs | 42 ++++++++++++++++--- PoweredSoft.DynamicLinq.Test/TestData.cs | 2 +- PoweredSoft.DynamicLinq/Constants.cs | 1 + .../Extensions/QueryableExtensions.cs | 2 +- .../Fluent/Group/GroupBuilder.cs | 7 ++++ .../Helpers/QueryableHelpers.cs | 13 +++--- 6 files changed, 52 insertions(+), 15 deletions(-) diff --git a/PoweredSoft.DynamicLinq.Test/GroupingTests.cs b/PoweredSoft.DynamicLinq.Test/GroupingTests.cs index fbfd06f..54d5e01 100644 --- a/PoweredSoft.DynamicLinq.Test/GroupingTests.cs +++ b/PoweredSoft.DynamicLinq.Test/GroupingTests.cs @@ -8,10 +8,22 @@ using PoweredSoft.DynamicLinq; namespace PoweredSoft.DynamicLinq.Test { - internal class TestStructure + internal class TestStructureCompare : IEqualityComparer { - public long ClientId { get; set; } - public decimal B { get; set; } + public bool Equals(TestStructure x, TestStructure y) + { + return x?.ClientId == y?.ClientId; + } + + public int GetHashCode(TestStructure obj) + { + return obj.ClientId; + } + } + + internal class TestStructure + { + public int ClientId { get; set; } } [TestClass] @@ -42,7 +54,22 @@ namespace PoweredSoft.DynamicLinq.Test var dynamicSyntax3 = TestData.Sales .AsQueryable() - .GroupBy(t => t.UseType(typeof(TestStructure)).Path("ClientId").Path("NetSales", "B")); + .GroupBy(t => t.UseType(typeof(TestStructure)).EqualityComparer(typeof(TestStructureCompare)).Path("ClientId")); + + var tryAs = dynamicSyntax3 as EnumerableQuery>; + var list = tryAs.Select(t => new + { + Key = t.Key, + Data = t.ToList() + }).ToList(); + + var list2 = TestData.Sales.GroupBy(t => new TestStructure { ClientId = t.ClientId }, new TestStructureCompare()).Select(t => new + { + Key = t.Key, + Data = t.ToList() + }).ToList(); + + int i = 0; /* @@ -57,8 +84,6 @@ namespace PoweredSoft.DynamicLinq.Test Sales = t.ToList() });*/ - - /* .Select(t => { @@ -72,5 +97,10 @@ namespace PoweredSoft.DynamicLinq.Test t.ToList("Sales"); });*/ } + + private object compare(MockSale arg) + { + throw new NotImplementedException(); + } } } diff --git a/PoweredSoft.DynamicLinq.Test/TestData.cs b/PoweredSoft.DynamicLinq.Test/TestData.cs index 2c93f42..4d6e669 100644 --- a/PoweredSoft.DynamicLinq.Test/TestData.cs +++ b/PoweredSoft.DynamicLinq.Test/TestData.cs @@ -19,7 +19,7 @@ namespace PoweredSoft.DynamicLinq.Test internal class MockSale { public long Id { get; set; } - public long ClientId { get; set; } + public int ClientId { get; set; } public MockClient Client { get; set; } public decimal GrossSales { get; set; } public decimal NetSales { get; set; } diff --git a/PoweredSoft.DynamicLinq/Constants.cs b/PoweredSoft.DynamicLinq/Constants.cs index 41f5e0b..98619da 100644 --- a/PoweredSoft.DynamicLinq/Constants.cs +++ b/PoweredSoft.DynamicLinq/Constants.cs @@ -44,6 +44,7 @@ namespace PoweredSoft.DynamicLinq internal static class Constants { internal static readonly MethodInfo GroupByMethod = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy"); + internal static readonly MethodInfo GroupByMethodWithEqualityComparer = typeof(Queryable).GetMethods().First(t => t.Name == "GroupBy" && t.GetParameters().Any(t2 => t2.Name == "comparer")); internal static readonly MethodInfo StringEqualWithComparisation = typeof(string).GetMethod("Equals", new Type[] { typeof(string), typeof(StringComparison) }); internal static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains"); internal static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }); diff --git a/PoweredSoft.DynamicLinq/Extensions/QueryableExtensions.cs b/PoweredSoft.DynamicLinq/Extensions/QueryableExtensions.cs index 62d4985..f0c4ed4 100644 --- a/PoweredSoft.DynamicLinq/Extensions/QueryableExtensions.cs +++ b/PoweredSoft.DynamicLinq/Extensions/QueryableExtensions.cs @@ -86,7 +86,7 @@ namespace PoweredSoft.DynamicLinq if (groupBuilder.Empty) throw new Exception("No group specified, please specify at least one group"); - return QueryableHelpers.GroupBy(query, type, groupBuilder.Parts, groupBuilder.Type); + return QueryableHelpers.GroupBy(query, type, groupBuilder.Parts, groupBuilder.Type, groupBuilder.EqualityComparerType); } } } diff --git a/PoweredSoft.DynamicLinq/Fluent/Group/GroupBuilder.cs b/PoweredSoft.DynamicLinq/Fluent/Group/GroupBuilder.cs index deaefd8..88f9ebc 100644 --- a/PoweredSoft.DynamicLinq/Fluent/Group/GroupBuilder.cs +++ b/PoweredSoft.DynamicLinq/Fluent/Group/GroupBuilder.cs @@ -10,6 +10,7 @@ namespace PoweredSoft.DynamicLinq.Fluent public List<(string path, string propertyName)> Parts { get; set; } = new List<(string path, string propertyName)>(); public Type Type { get; set; } public bool Empty => !Parts.Any(); + public Type EqualityComparerType { get; set; } public GroupBuilder Path(string path, string propertyName = null) { @@ -37,5 +38,11 @@ namespace PoweredSoft.DynamicLinq.Fluent Type = type; return this; } + + public GroupBuilder EqualityComparer(Type type) + { + EqualityComparerType = type; + return this; + } } } diff --git a/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs b/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs index 9bffde4..796777d 100644 --- a/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs +++ b/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs @@ -77,7 +77,7 @@ namespace PoweredSoft.DynamicLinq.Helpers return ret; } - public static IQueryable GroupBy(IQueryable query, Type type, List<(string path, string propertyName)> parts, Type groupToType = null) + public static IQueryable GroupBy(IQueryable query, Type type, List<(string path, string propertyName)> parts, Type groupToType = null, Type equalityCompareType = null) { // EXPRESSION var parameter = Expression.Parameter(type, "t"); @@ -93,8 +93,7 @@ namespace PoweredSoft.DynamicLinq.Helpers partExpressions.Add((partExpression, part.propertyName)); }); - var anonymousType = groupToType ?? TypeHelpers.CreateSimpleAnonymousType(fields); - + var keyType = groupToType ?? TypeHelpers.CreateSimpleAnonymousType(fields); /* var constructorTypes = fields.Select(t => t.type).ToArray(); @@ -105,12 +104,12 @@ namespace PoweredSoft.DynamicLinq.Helpers var groupByExpression = Expression.Call(genericMethod, query.Expression, lambda); var result = query.Provider.CreateQuery(groupByExpression);*/ - var ctor = Expression.New(anonymousType); - var bindings = partExpressions.Select(partExpression => Expression.Bind(anonymousType.GetProperty(partExpression.propertyName), partExpression.expression)).ToList(); + var ctor = Expression.New(keyType); + var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToList(); var mi = Expression.MemberInit(ctor, bindings.ToArray()); var lambda = Expression.Lambda(mi, parameter); - var genericMethod = Constants.GroupByMethod.MakeGenericMethod(type, anonymousType); - var groupByExpression = Expression.Call(genericMethod, query.Expression, lambda); + var genericMethod = equalityCompareType == null ? Constants.GroupByMethod.MakeGenericMethod(type, keyType) : Constants.GroupByMethodWithEqualityComparer.MakeGenericMethod(type, keyType); //, Activator.CreateInstance(equalityCompareType)); + var groupByExpression = equalityCompareType == null ? Expression.Call(genericMethod, query.Expression, lambda) : Expression.Call(genericMethod, query.Expression, lambda, Expression.New(equalityCompareType)); var result = query.Provider.CreateQuery(groupByExpression); return result; }