Merge branch 'release/1.1.6'
This commit is contained in:
		
						commit
						da85bfee88
					
				| @ -8,6 +8,7 @@ using PoweredSoft.DynamicLinq; | ||||
| using PoweredSoft.DynamicLinq.Dal; | ||||
| using System.Diagnostics; | ||||
| using PoweredSoft.DynamicLinq.Test.Helpers; | ||||
| using System.Collections; | ||||
| 
 | ||||
| namespace PoweredSoft.DynamicLinq.Test | ||||
| { | ||||
| @ -72,7 +73,13 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                     LongCount = t.LongCount(), | ||||
|                     NetSales = t.Sum(t2 => t2.NetSales), | ||||
|                     TaxAverage = t.Average(t2 => t2.Tax), | ||||
|                     Sales = t.ToList() | ||||
|                     Sales = t.ToList(), | ||||
|                     MaxNetSales = t.Max(t2 => t2.NetSales), | ||||
|                     MinNetSales = t.Min(t2 => t2.NetSales), | ||||
|                     First = t.First(), | ||||
|                     Last = t.Last(), | ||||
|                     FirstOrDefault = t.FirstOrDefault(), | ||||
|                     LastOrDefault = t.LastOrDefault() | ||||
|                 }) | ||||
|                 .ToList(); | ||||
| 
 | ||||
| @ -86,6 +93,12 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                    t.LongCount("LongCount"); | ||||
|                    t.Sum("NetSales"); | ||||
|                    t.Average("Tax", "TaxAverage"); | ||||
|                    t.Max("NetSales", "MaxNetSales"); | ||||
|                    t.Min("NetSales", "MinNetSales"); | ||||
|                    t.First("First"); | ||||
|                    t.Last("Last"); | ||||
|                    t.FirstOrDefault("FirstOrDefault"); | ||||
|                    t.LastOrDefault("LastOrDefault"); | ||||
|                    t.ToList("Sales"); | ||||
|                }) | ||||
|                .ToDynamicClassList(); | ||||
| @ -100,6 +113,14 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                 Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count")); | ||||
|                 Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount")); | ||||
|                 Assert.AreEqual(left.TaxAverage, right.GetDynamicPropertyValue("TaxAverage")); | ||||
|                 Assert.AreEqual(left.MinNetSales, right.GetDynamicPropertyValue("MinNetSales")); | ||||
|                 Assert.AreEqual(left.MaxNetSales, right.GetDynamicPropertyValue("MaxNetSales")); | ||||
| 
 | ||||
|                 Assert.AreEqual(left.First, right.GetDynamicPropertyValue("First")); | ||||
|                 Assert.AreEqual(left.FirstOrDefault, right.GetDynamicPropertyValue("FirstOrDefault")); | ||||
|                 Assert.AreEqual(left.Last, right.GetDynamicPropertyValue("Last")); | ||||
|                 Assert.AreEqual(left.LastOrDefault, right.GetDynamicPropertyValue("LastOrDefault")); | ||||
| 
 | ||||
|                 QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue<List<MockSale>>("Sales").AsQueryable()); | ||||
|             } | ||||
|         } | ||||
| @ -149,5 +170,84 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                 QueryableAssert.AreEqual(left.Sales.AsQueryable(), right.GetDynamicPropertyValue<List<MockSale>>("Sales").AsQueryable()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void GroupWithoutNullCheckComplex() | ||||
|         { | ||||
|             var limitResult = TestData.Authors.Where(t => t.Posts != null).AsQueryable(); | ||||
| 
 | ||||
|             var posts = limitResult | ||||
|                 .GroupBy(t => new | ||||
|                 { | ||||
|                     Titles = t.Posts.Select(t2 => t2.Title) | ||||
|                 }) | ||||
|                 .Select(t => new | ||||
|                 { | ||||
|                     Titles = t.Key.Titles, | ||||
|                     Data = t.ToList() | ||||
|                 }) | ||||
|                 .ToList(); | ||||
| 
 | ||||
|             var posts2 = limitResult | ||||
|                 .GroupBy(gb => gb.Path("Posts.Title", "Titles")) | ||||
|                 .Select(sb => | ||||
|                 { | ||||
|                     sb.Key("Titles"); | ||||
|                     sb.ToList("Data"); | ||||
|                 }) | ||||
|                 .ToDynamicClassList(); | ||||
| 
 | ||||
|             Assert.AreEqual(posts.Count, posts2.Count); | ||||
|             for(var i  = 0; i < posts.Count; i++) | ||||
|             { | ||||
|                 var expected = posts[0]; | ||||
|                 var actual = posts2[0]; | ||||
| 
 | ||||
|                 var titles = actual.GetDynamicPropertyValue("Titles") as ICollection; | ||||
| 
 | ||||
|                 CollectionAssert.AreEqual(expected.Titles as ICollection, titles); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void GroupWithNullCheckComplex() | ||||
|         { | ||||
|             var limitResult = TestData.Authors.AsQueryable(); | ||||
| 
 | ||||
|             var posts = limitResult | ||||
|                 .GroupBy(t => new | ||||
|                 { | ||||
|                     Titles = t.Posts == null ? new List<string>() : t.Posts.Select(t2 => t2.Title) | ||||
|                 }) | ||||
|                 .Select(t => new | ||||
|                 { | ||||
|                     Titles = t.Key.Titles, | ||||
|                     Data = t.ToList() | ||||
|                 }) | ||||
|                 .ToList(); | ||||
| 
 | ||||
|             var tempQueryable = limitResult | ||||
|                 .GroupBy(gb => gb.NullChecking().Path("Posts.Title", "Titles")); | ||||
| 
 | ||||
| 
 | ||||
|             var posts2 = tempQueryable  | ||||
|                 .Select(sb => | ||||
|                 { | ||||
|                     sb.Key("Titles"); | ||||
|                     sb.ToList("Data"); | ||||
|                 }) | ||||
|                 .ToDynamicClassList(); | ||||
| 
 | ||||
|             Assert.AreEqual(posts.Count, posts2.Count); | ||||
|             for (var i = 0; i < posts.Count; i++) | ||||
|             { | ||||
|                 var expected = posts[0]; | ||||
|                 var actual = posts2[0]; | ||||
| 
 | ||||
|                 var titles = actual.GetDynamicPropertyValue("Titles") as ICollection; | ||||
| 
 | ||||
|                 CollectionAssert.AreEqual(expected.Titles as ICollection, titles); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -47,7 +47,16 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                 { | ||||
|                     Id = t.Id, | ||||
|                     FirstNames = t.Bs.SelectMany(t2 => t2.FirstNames).ToList(), | ||||
|                     FirstNamesLists = t.Bs.Select(t2 => t2.FirstNames).ToList() | ||||
|                     FirstNamesLists = t.Bs.Select(t2 => t2.FirstNames).ToList(), | ||||
|                     FirstFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).First(), | ||||
|                     FirstOrDefaultFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).FirstOrDefault(), | ||||
|                     LastFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).Last(), | ||||
|                     LastOrDefaultFirstName = t.Bs.SelectMany(t2 => t2.FirstNames).LastOrDefault(), | ||||
| 
 | ||||
|                     FirstFirstNameList = t.Bs.Select(t2 => t2.FirstNames).First(), | ||||
|                     FirstOrDefaultFirstNameList = t.Bs.Select(t2 => t2.FirstNames).FirstOrDefault(), | ||||
|                     LastFirstNameList = t.Bs.Select(t2 => t2.FirstNames).Last(), | ||||
|                     LastOrDefaultFirstNameList = t.Bs.Select(t2 => t2.FirstNames).LastOrDefault() | ||||
|                 }); | ||||
|              | ||||
|             var regularSyntax = regularSyntaxA.ToList(); | ||||
| @ -57,8 +66,17 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|                 .Select(t => | ||||
|                 { | ||||
|                     t.Path("Id"); | ||||
|                     t.PathToList("Bs.FirstNames", "FirstNames", SelectCollectionHandling.Flatten); | ||||
|                     t.PathToList("Bs.FirstNames", "FirstNamesLists", SelectCollectionHandling.LeaveAsIs); | ||||
|                     t.ToList("Bs.FirstNames", "FirstNames", SelectCollectionHandling.Flatten); | ||||
|                     t.ToList("Bs.FirstNames", "FirstNamesLists", SelectCollectionHandling.LeaveAsIs); | ||||
|                     t.First("Bs.FirstNames", "FirstFirstName", SelectCollectionHandling.Flatten); | ||||
|                     t.FirstOrDefault("Bs.FirstNames", "FirstOrDefaultFirstName", SelectCollectionHandling.Flatten); | ||||
|                     t.Last("Bs.FirstNames", "LastFirstName", SelectCollectionHandling.Flatten); | ||||
|                     t.LastOrDefault("Bs.FirstNames", "LastOrDefaultFirstName", SelectCollectionHandling.Flatten); | ||||
| 
 | ||||
|                     t.First("Bs.FirstNames", "FirstFirstNameList", SelectCollectionHandling.LeaveAsIs); | ||||
|                     t.FirstOrDefault("Bs.FirstNames", "FirstOrDefaultFirstNameList", SelectCollectionHandling.LeaveAsIs); | ||||
|                     t.Last("Bs.FirstNames", "LastFirstNameList", SelectCollectionHandling.LeaveAsIs); | ||||
|                     t.LastOrDefault("Bs.FirstNames", "LastOrDefaultFirstNameList", SelectCollectionHandling.LeaveAsIs); | ||||
|                 }) | ||||
|                 .ToDynamicClassList(); | ||||
| 
 | ||||
| @ -66,9 +84,22 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|             for(var i = 0; i < regularSyntax.Count; i++) | ||||
|             { | ||||
|                 Assert.AreEqual(regularSyntax[i].Id, dynamicSyntax[i].GetDynamicPropertyValue<int>("Id")); | ||||
|                 Assert.AreEqual(regularSyntax[i].FirstFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("FirstFirstName")); | ||||
|                 Assert.AreEqual(regularSyntax[i].FirstOrDefaultFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("FirstOrDefaultFirstName")); | ||||
|                 Assert.AreEqual(regularSyntax[i].LastFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("LastFirstName")); | ||||
|                 Assert.AreEqual(regularSyntax[i].LastOrDefaultFirstName, dynamicSyntax[i].GetDynamicPropertyValue<string>("LastOrDefaultFirstName")); | ||||
| 
 | ||||
|                 CollectionAssert.AreEqual(regularSyntax[i].FirstFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("FirstFirstNameList")); | ||||
|                 CollectionAssert.AreEqual(regularSyntax[i].FirstOrDefaultFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("FirstOrDefaultFirstNameList")); | ||||
|                 CollectionAssert.AreEqual(regularSyntax[i].LastFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("LastFirstNameList")); | ||||
|                 CollectionAssert.AreEqual(regularSyntax[i].LastOrDefaultFirstNameList, dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("LastOrDefaultFirstNameList")); | ||||
| 
 | ||||
| 
 | ||||
|                 QueryableAssert.AreEqual(regularSyntax[i].FirstNames.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("FirstNames").AsQueryable()); | ||||
| 
 | ||||
| 
 | ||||
|                  | ||||
| 
 | ||||
|                 var left = regularSyntax[i].FirstNamesLists; | ||||
|                 var right = dynamicSyntax[i].GetDynamicPropertyValue<List<List<string>>>("FirstNamesLists"); | ||||
|                 Assert.AreEqual(left.Count, right.Count); | ||||
| @ -95,7 +126,7 @@ namespace PoweredSoft.DynamicLinq.Test | ||||
|             var querySelect = query.Select(t => | ||||
|             { | ||||
|                 t.NullChecking(true); | ||||
|                 t.PathToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten); | ||||
|                 t.ToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten); | ||||
|             }); | ||||
| 
 | ||||
|             var b = querySelect.ToDynamicClassList(); | ||||
|  | ||||
| @ -49,8 +49,13 @@ namespace PoweredSoft.DynamicLinq | ||||
|         Sum, | ||||
|         Average, | ||||
|         ToList, | ||||
|         PathToList, | ||||
|         Path | ||||
|         Path, | ||||
|         Min, | ||||
|         Max, | ||||
|         LastOrDefault, | ||||
|         FirstOrDefault, | ||||
|         Last, | ||||
|         First, | ||||
|     } | ||||
| 
 | ||||
|     public enum SelectCollectionHandling | ||||
|  | ||||
| @ -15,6 +15,8 @@ namespace PoweredSoft.DynamicLinq.Fluent | ||||
| 
 | ||||
|         public IQueryable Query { get; protected set; } | ||||
| 
 | ||||
|         public bool IsNullCheckingEnabled { get; protected set; } = false; | ||||
| 
 | ||||
|         public GroupBuilder(IQueryable query) | ||||
|         { | ||||
|             Query = query; | ||||
| @ -41,6 +43,12 @@ namespace PoweredSoft.DynamicLinq.Fluent | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public GroupBuilder NullChecking(bool nullChecking = true) | ||||
|         { | ||||
|             IsNullCheckingEnabled = nullChecking; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public GroupBuilder UseType(Type type) | ||||
|         { | ||||
|             Type = type; | ||||
| @ -58,7 +66,7 @@ namespace PoweredSoft.DynamicLinq.Fluent | ||||
|             if (Empty) | ||||
|                 throw new Exception("No group specified, please specify at least one group"); | ||||
| 
 | ||||
|             var ret = QueryableHelpers.GroupBy(Query, Query.ElementType, Parts, Type, EqualityComparerType); | ||||
|             var ret = QueryableHelpers.GroupBy(Query, Query.ElementType, Parts, groupToType: Type, equalityCompareType: EqualityComparerType, nullChecking: IsNullCheckingEnabled); | ||||
|             return ret; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -42,25 +42,11 @@ namespace PoweredSoft.DynamicLinq.Fluent | ||||
|                 throw new Exception($"{propertyName} is already used"); | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Key(string propertyName, string path = null) | ||||
|         public SelectBuilder Aggregate(string path, SelectTypes type, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
|             if (propertyName == null && path == null) | ||||
|                 throw new Exception("if property name is not specified, a path must be supplied."); | ||||
| 
 | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
| 
 | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 Path = path == null ? "Key" : $"Key.{path}", | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.Key | ||||
|             }); | ||||
| 
 | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Aggregate(string path, SelectTypes type, string propertyName = null) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
| 
 | ||||
| @ -70,112 +56,46 @@ namespace PoweredSoft.DynamicLinq.Fluent | ||||
|             { | ||||
|                 Path = path, | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = type | ||||
|             }); | ||||
| 
 | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Path(string path, string propertyName = null) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
| 
 | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
| 
 | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 Path = path,  | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.Path | ||||
|             }); | ||||
| 
 | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Count(string propertyName) | ||||
|         { | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.Count | ||||
|             }); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder LongCount(string propertyName) | ||||
|         { | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.LongCount | ||||
|             }); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Sum(string path, string propertyName = null) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
| 
 | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
| 
 | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 Path = path, | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.Sum | ||||
|             }); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Average(string path, string propertyName = null) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
| 
 | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
| 
 | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 Path = path, | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.Average | ||||
|             }); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder ToList(string propertyName) | ||||
|         { | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.ToList | ||||
|             }); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder PathToList(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|         { | ||||
|             if (propertyName == null) | ||||
|                 propertyName = path.Split('.').LastOrDefault(); | ||||
| 
 | ||||
|             ThrowIfUsedOrEmpty(propertyName); | ||||
| 
 | ||||
|             Parts.Add(new SelectPart | ||||
|             { | ||||
|                 Path = path, | ||||
|                 PropertyName = propertyName, | ||||
|                 SelectType = SelectTypes.PathToList, | ||||
|                 SelectType = type, | ||||
|                 SelectCollectionHandling = selectCollectionHandling | ||||
|             }); | ||||
| 
 | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public SelectBuilder Key(string propertyName, string path = null) => Aggregate(path == null ? "Key" : $"Key.{path}", SelectTypes.Key, propertyName); | ||||
|         public SelectBuilder Path(string path, string propertyName = null) => Aggregate(path, SelectTypes.Path, propertyName); | ||||
|         public SelectBuilder Count(string propertyName) => Aggregate(null, SelectTypes.Count, propertyName); | ||||
|         public SelectBuilder LongCount(string propertyName) => Aggregate(null, SelectTypes.LongCount, propertyName); | ||||
|         public SelectBuilder Sum(string path, string propertyName = null) => Aggregate(path, SelectTypes.Sum, propertyName); | ||||
|         public SelectBuilder Average(string path, string propertyName = null) => Aggregate(path, SelectTypes.Average, propertyName); | ||||
|         public SelectBuilder Min(string path, string propertyName = null) => Aggregate(path, SelectTypes.Min, propertyName); | ||||
|         public SelectBuilder Max(string path, string propertyName = null) => Aggregate(path, SelectTypes.Max, propertyName); | ||||
|         public SelectBuilder ToList(string propertyName) => Aggregate(null, SelectTypes.ToList, propertyName); | ||||
|         public SelectBuilder LastOrDefault(string propertyName) => Aggregate(null, SelectTypes.LastOrDefault, propertyName); | ||||
|         public SelectBuilder FirstOrDefault(string propertyName) => Aggregate(null, SelectTypes.FirstOrDefault, propertyName); | ||||
|         public SelectBuilder Last(string propertyName) => Aggregate(null, SelectTypes.Last, propertyName); | ||||
|         public SelectBuilder First(string propertyName) => Aggregate(null, SelectTypes.First, propertyName); | ||||
| 
 | ||||
|         [System.Obsolete("Use ToList instead", true)] | ||||
|         public SelectBuilder PathToList(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|                 => ToList(path, propertyName, selectCollectionHandling); | ||||
| 
 | ||||
|         public SelectBuilder ToList(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|             => Aggregate(path, SelectTypes.ToList, propertyName: propertyName, selectCollectionHandling: selectCollectionHandling); | ||||
| 
 | ||||
|         public SelectBuilder First(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|             => Aggregate(path, SelectTypes.First, propertyName: propertyName, selectCollectionHandling: selectCollectionHandling); | ||||
| 
 | ||||
|         public SelectBuilder FirstOrDefault(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|             => Aggregate(path, SelectTypes.FirstOrDefault, propertyName: propertyName, selectCollectionHandling: selectCollectionHandling); | ||||
| 
 | ||||
|         public SelectBuilder Last(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|             => Aggregate(path, SelectTypes.Last, propertyName: propertyName, selectCollectionHandling: selectCollectionHandling); | ||||
| 
 | ||||
|         public SelectBuilder LastOrDefault(string path, string propertyName = null, SelectCollectionHandling selectCollectionHandling = SelectCollectionHandling.LeaveAsIs) | ||||
|             => Aggregate(path, SelectTypes.LastOrDefault, propertyName: propertyName, selectCollectionHandling: selectCollectionHandling); | ||||
| 
 | ||||
|         public virtual IQueryable Build() | ||||
|         { | ||||
|             if (Empty) | ||||
|  | ||||
| @ -83,7 +83,7 @@ namespace PoweredSoft.DynamicLinq.Helpers | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
|         public static IQueryable GroupBy(IQueryable query, Type type, List<(string path, string propertyName)> parts, Type groupToType = null, Type equalityCompareType = null) | ||||
|         public static IQueryable GroupBy(IQueryable query, Type type, List<(string path, string propertyName)> parts, Type groupToType = null, Type equalityCompareType = null, bool nullChecking = false) | ||||
|         { | ||||
|             // EXPRESSION | ||||
|             var parameter = Expression.Parameter(type, "t"); | ||||
| @ -94,22 +94,12 @@ namespace PoweredSoft.DynamicLinq.Helpers | ||||
|             // resolve part expression and create the fields inside the anonymous type. | ||||
|             parts.ForEach(part => | ||||
|             { | ||||
|                 var partExpression = ResolvePathForExpression(parameter, part.path); | ||||
|                 var partExpression = CreateSelectExpression(query, parameter, SelectTypes.Path, part.path, SelectCollectionHandling.LeaveAsIs, nullChecking: nullChecking); | ||||
|                 fields.Add((partExpression.Type, part.propertyName)); | ||||
|                 partExpressions.Add((partExpression, part.propertyName)); | ||||
|             }); | ||||
| 
 | ||||
|             var keyType = groupToType ?? DynamicClassFactory.CreateType(fields); | ||||
| 
 | ||||
|             /* | ||||
|             var constructorTypes = fields.Select(t => t.type).ToArray(); | ||||
|             var constructor = anonymousType.GetConstructor(constructorTypes); | ||||
|             var newExpression = Expression.New(constructor, partExpressions); | ||||
|             var genericMethod = Constants.GroupByMethod.MakeGenericMethod(type, anonymousType); | ||||
|             var lambda = Expression.Lambda(newExpression, parameter); | ||||
|             var groupByExpression = Expression.Call(genericMethod, query.Expression, lambda); | ||||
|             var result = query.Provider.CreateQuery(groupByExpression);*/ | ||||
| 
 | ||||
|             var ctor = Expression.New(keyType); | ||||
|             var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToArray(); | ||||
|             var mi = Expression.MemberInit(ctor, bindings); | ||||
| @ -185,12 +175,54 @@ namespace PoweredSoft.DynamicLinq.Helpers | ||||
|                 var body = Expression.Call(typeof(Enumerable), "Sum", new[] { notGroupedType }, parameter, innerMemberLambda); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.Min) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var innerParameter = Expression.Parameter(notGroupedType); | ||||
|                 var innerMemberExpression = ResolvePathForExpression(innerParameter, path); | ||||
|                 var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter); | ||||
|                 var body = Expression.Call(typeof(Enumerable), "Min", new[] { notGroupedType }, parameter, innerMemberLambda); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.Max) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var innerParameter = Expression.Parameter(notGroupedType); | ||||
|                 var innerMemberExpression = ResolvePathForExpression(innerParameter, path); | ||||
|                 var innerMemberLambda = Expression.Lambda(innerMemberExpression, innerParameter); | ||||
|                 var body = Expression.Call(typeof(Enumerable), "Max", new[] { notGroupedType }, parameter, innerMemberLambda); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.ToList) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, parameter); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.First) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var body = Expression.Call(typeof(Enumerable), "First", new[] { notGroupedType }, parameter); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.Last) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var body = Expression.Call(typeof(Enumerable), "Last", new[] { notGroupedType }, parameter); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.FirstOrDefault) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var body = Expression.Call(typeof(Enumerable), "FirstOrDefault", new[] { notGroupedType }, parameter); | ||||
|                 return body; | ||||
|             } | ||||
|             else if (selectType == SelectTypes.LastOrDefault) | ||||
|             { | ||||
|                 var notGroupedType = parameter.Type.GenericTypeArguments[1]; | ||||
|                 var body = Expression.Call(typeof(Enumerable), "LastOrDefault", new[] { notGroupedType }, parameter); | ||||
|                 return body; | ||||
|             } | ||||
| 
 | ||||
|             throw new NotSupportedException($"unkown select type {selectType}"); | ||||
|         } | ||||
| @ -214,25 +246,37 @@ namespace PoweredSoft.DynamicLinq.Helpers | ||||
|                 resolver.Resolve(); | ||||
|                 return resolver.GetResultBodyExpression(); | ||||
|             } | ||||
|             else if (selectType == SelectTypes.PathToList) | ||||
|             { | ||||
|                 var parser = new ExpressionParser(parameter, path); | ||||
|                 var resolver = new PathExpressionResolver(parser); | ||||
|                 resolver.NullChecking = nullChecking; | ||||
|                 resolver.CollectionHandling = selectCollectionHandling; | ||||
|                 resolver.Resolve(); | ||||
|                 var expr = (resolver.Result as LambdaExpression).Body; | ||||
|                 var notGroupedType = expr.Type.GenericTypeArguments.FirstOrDefault(); | ||||
|                 if (notGroupedType == null) | ||||
|                     throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}"); | ||||
|             else if (selectType == SelectTypes.ToList) | ||||
|                 return CreateSelectExpressionPathWithMethodName(parameter, path, selectCollectionHandling, nullChecking, "ToList"); | ||||
|             else if (selectType == SelectTypes.First) | ||||
|                 return CreateSelectExpressionPathWithMethodName(parameter, path, selectCollectionHandling, nullChecking, "First"); | ||||
|             else if (selectType == SelectTypes.FirstOrDefault) | ||||
|                 return CreateSelectExpressionPathWithMethodName(parameter, path, selectCollectionHandling, nullChecking, "FirstOrDefault"); | ||||
|             else if (selectType == SelectTypes.Last) | ||||
|                 return CreateSelectExpressionPathWithMethodName(parameter, path, selectCollectionHandling, nullChecking, "Last"); | ||||
|             else if (selectType == SelectTypes.LastOrDefault) | ||||
|                 return CreateSelectExpressionPathWithMethodName(parameter, path, selectCollectionHandling, nullChecking, "LastOrDefault"); | ||||
| 
 | ||||
|                 var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, expr) as Expression; | ||||
|                 return body; | ||||
|             } | ||||
| 
 | ||||
|             throw new NotSupportedException($"unkown select type {selectType}"); | ||||
|         } | ||||
| 
 | ||||
|         private static Expression CreateSelectExpressionPathWithMethodName(ParameterExpression parameter, string path, SelectCollectionHandling selectCollectionHandling, bool nullChecking, string methodName) | ||||
|         { | ||||
|             var parser = new ExpressionParser(parameter, path); | ||||
|             var resolver = new PathExpressionResolver(parser); | ||||
|             resolver.NullChecking = nullChecking; | ||||
|             resolver.CollectionHandling = selectCollectionHandling; | ||||
|             resolver.Resolve(); | ||||
|             var expr = (resolver.Result as LambdaExpression).Body; | ||||
|             var notGroupedType = expr.Type.GenericTypeArguments.FirstOrDefault(); | ||||
|             if (notGroupedType == null) | ||||
|                 throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}"); | ||||
| 
 | ||||
|             var body = Expression.Call(typeof(Enumerable), methodName, new[] { notGroupedType }, expr) as Expression; | ||||
|             return body; | ||||
|         } | ||||
| 
 | ||||
|         private static bool IsGrouping(IQueryable query) | ||||
|         { | ||||
|             // TODO needs to be alot better than this, but it will do for now. | ||||
|  | ||||
| @ -99,11 +99,13 @@ someQsomeQueryableOfTueryable.Count(); | ||||
| 
 | ||||
| ### Select  | ||||
| 
 | ||||
| > Note **PathToList** has been renamed to just **ToList** it seemed redudant, sorry for breaking change. | ||||
| 
 | ||||
| ```csharp | ||||
| var querySelect = query.Select(t => | ||||
| { | ||||
| t.NullChecking(true); // not obligated but usefull for in memory queries.  | ||||
| t.PathToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten); | ||||
| t.ToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten); | ||||
| t.Path("FirstName"); | ||||
| t.Path("LastName", "ChangePropertyNameOfLastName"); | ||||
| }); | ||||
| @ -190,6 +192,8 @@ Assert.AreEqual(first?.FirstName, "David"); | ||||
| 
 | ||||
| ### How it can be used in a web api | ||||
| 
 | ||||
| > I highly suggest looking @ https://github.com/poweredsoft/dynamicquery if you are interested in this sample. | ||||
| 
 | ||||
| ```csharp | ||||
| [HttpGet][Route("FindClients")] | ||||
| public IHttpActionResult FindClients(string filterField = null, string filterValue = null,  | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user