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 PoweredSoft.DynamicLinq.Dal;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using PoweredSoft.DynamicLinq.Test.Helpers;
|
using PoweredSoft.DynamicLinq.Test.Helpers;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace PoweredSoft.DynamicLinq.Test
|
namespace PoweredSoft.DynamicLinq.Test
|
||||||
{
|
{
|
||||||
@ -72,7 +73,13 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
LongCount = t.LongCount(),
|
LongCount = t.LongCount(),
|
||||||
NetSales = t.Sum(t2 => t2.NetSales),
|
NetSales = t.Sum(t2 => t2.NetSales),
|
||||||
TaxAverage = t.Average(t2 => t2.Tax),
|
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();
|
.ToList();
|
||||||
|
|
||||||
@ -86,6 +93,12 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
t.LongCount("LongCount");
|
t.LongCount("LongCount");
|
||||||
t.Sum("NetSales");
|
t.Sum("NetSales");
|
||||||
t.Average("Tax", "TaxAverage");
|
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");
|
t.ToList("Sales");
|
||||||
})
|
})
|
||||||
.ToDynamicClassList();
|
.ToDynamicClassList();
|
||||||
@ -100,6 +113,14 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count"));
|
Assert.AreEqual(left.Count, right.GetDynamicPropertyValue("Count"));
|
||||||
Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount"));
|
Assert.AreEqual(left.LongCount, right.GetDynamicPropertyValue("LongCount"));
|
||||||
Assert.AreEqual(left.TaxAverage, right.GetDynamicPropertyValue("TaxAverage"));
|
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());
|
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());
|
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,
|
Id = t.Id,
|
||||||
FirstNames = t.Bs.SelectMany(t2 => t2.FirstNames).ToList(),
|
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();
|
var regularSyntax = regularSyntaxA.ToList();
|
||||||
@ -57,8 +66,17 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
.Select(t =>
|
.Select(t =>
|
||||||
{
|
{
|
||||||
t.Path("Id");
|
t.Path("Id");
|
||||||
t.PathToList("Bs.FirstNames", "FirstNames", SelectCollectionHandling.Flatten);
|
t.ToList("Bs.FirstNames", "FirstNames", SelectCollectionHandling.Flatten);
|
||||||
t.PathToList("Bs.FirstNames", "FirstNamesLists", SelectCollectionHandling.LeaveAsIs);
|
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();
|
.ToDynamicClassList();
|
||||||
|
|
||||||
@ -66,9 +84,22 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
for(var i = 0; i < regularSyntax.Count; i++)
|
for(var i = 0; i < regularSyntax.Count; i++)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(regularSyntax[i].Id, dynamicSyntax[i].GetDynamicPropertyValue<int>("Id"));
|
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());
|
QueryableAssert.AreEqual(regularSyntax[i].FirstNames.AsQueryable(), dynamicSyntax[i].GetDynamicPropertyValue<List<string>>("FirstNames").AsQueryable());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var left = regularSyntax[i].FirstNamesLists;
|
var left = regularSyntax[i].FirstNamesLists;
|
||||||
var right = dynamicSyntax[i].GetDynamicPropertyValue<List<List<string>>>("FirstNamesLists");
|
var right = dynamicSyntax[i].GetDynamicPropertyValue<List<List<string>>>("FirstNamesLists");
|
||||||
Assert.AreEqual(left.Count, right.Count);
|
Assert.AreEqual(left.Count, right.Count);
|
||||||
@ -95,7 +126,7 @@ namespace PoweredSoft.DynamicLinq.Test
|
|||||||
var querySelect = query.Select(t =>
|
var querySelect = query.Select(t =>
|
||||||
{
|
{
|
||||||
t.NullChecking(true);
|
t.NullChecking(true);
|
||||||
t.PathToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten);
|
t.ToList("Posts.Comments.CommentLikes", selectCollectionHandling: SelectCollectionHandling.Flatten);
|
||||||
});
|
});
|
||||||
|
|
||||||
var b = querySelect.ToDynamicClassList();
|
var b = querySelect.ToDynamicClassList();
|
||||||
|
@ -49,8 +49,13 @@ namespace PoweredSoft.DynamicLinq
|
|||||||
Sum,
|
Sum,
|
||||||
Average,
|
Average,
|
||||||
ToList,
|
ToList,
|
||||||
PathToList,
|
Path,
|
||||||
Path
|
Min,
|
||||||
|
Max,
|
||||||
|
LastOrDefault,
|
||||||
|
FirstOrDefault,
|
||||||
|
Last,
|
||||||
|
First,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SelectCollectionHandling
|
public enum SelectCollectionHandling
|
||||||
|
@ -15,6 +15,8 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
|
|
||||||
public IQueryable Query { get; protected set; }
|
public IQueryable Query { get; protected set; }
|
||||||
|
|
||||||
|
public bool IsNullCheckingEnabled { get; protected set; } = false;
|
||||||
|
|
||||||
public GroupBuilder(IQueryable query)
|
public GroupBuilder(IQueryable query)
|
||||||
{
|
{
|
||||||
Query = query;
|
Query = query;
|
||||||
@ -41,6 +43,12 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GroupBuilder NullChecking(bool nullChecking = true)
|
||||||
|
{
|
||||||
|
IsNullCheckingEnabled = nullChecking;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public GroupBuilder UseType(Type type)
|
public GroupBuilder UseType(Type type)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
@ -58,7 +66,7 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
if (Empty)
|
if (Empty)
|
||||||
throw new Exception("No group specified, please specify at least one group");
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,25 +42,11 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
throw new Exception($"{propertyName} is already used");
|
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)
|
if (propertyName == null && path == null)
|
||||||
propertyName = path.Split('.').LastOrDefault();
|
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)
|
if (propertyName == null)
|
||||||
propertyName = path.Split('.').LastOrDefault();
|
propertyName = path.Split('.').LastOrDefault();
|
||||||
|
|
||||||
@ -70,112 +56,46 @@ namespace PoweredSoft.DynamicLinq.Fluent
|
|||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
PropertyName = propertyName,
|
PropertyName = propertyName,
|
||||||
SelectType = type
|
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,
|
|
||||||
SelectCollectionHandling = selectCollectionHandling
|
SelectCollectionHandling = selectCollectionHandling
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
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()
|
public virtual IQueryable Build()
|
||||||
{
|
{
|
||||||
if (Empty)
|
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
|
// EXPRESSION
|
||||||
var parameter = Expression.Parameter(type, "t");
|
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.
|
// resolve part expression and create the fields inside the anonymous type.
|
||||||
parts.ForEach(part =>
|
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));
|
fields.Add((partExpression.Type, part.propertyName));
|
||||||
partExpressions.Add((partExpression, part.propertyName));
|
partExpressions.Add((partExpression, part.propertyName));
|
||||||
});
|
});
|
||||||
|
|
||||||
var keyType = groupToType ?? DynamicClassFactory.CreateType(fields);
|
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 ctor = Expression.New(keyType);
|
||||||
var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToArray();
|
var bindings = partExpressions.Select(partExpression => Expression.Bind(keyType.GetProperty(partExpression.propertyName), partExpression.expression)).ToArray();
|
||||||
var mi = Expression.MemberInit(ctor, bindings);
|
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);
|
var body = Expression.Call(typeof(Enumerable), "Sum", new[] { notGroupedType }, parameter, innerMemberLambda);
|
||||||
return body;
|
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)
|
else if (selectType == SelectTypes.ToList)
|
||||||
{
|
{
|
||||||
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
var notGroupedType = parameter.Type.GenericTypeArguments[1];
|
||||||
var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, parameter);
|
var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, parameter);
|
||||||
return body;
|
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}");
|
throw new NotSupportedException($"unkown select type {selectType}");
|
||||||
}
|
}
|
||||||
@ -214,7 +246,22 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
resolver.Resolve();
|
resolver.Resolve();
|
||||||
return resolver.GetResultBodyExpression();
|
return resolver.GetResultBodyExpression();
|
||||||
}
|
}
|
||||||
else if (selectType == SelectTypes.PathToList)
|
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");
|
||||||
|
|
||||||
|
|
||||||
|
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 parser = new ExpressionParser(parameter, path);
|
||||||
var resolver = new PathExpressionResolver(parser);
|
var resolver = new PathExpressionResolver(parser);
|
||||||
@ -226,13 +273,10 @@ namespace PoweredSoft.DynamicLinq.Helpers
|
|||||||
if (notGroupedType == null)
|
if (notGroupedType == null)
|
||||||
throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}");
|
throw new Exception($"Path must be a Enumerable<T> but its a {expr.Type}");
|
||||||
|
|
||||||
var body = Expression.Call(typeof(Enumerable), "ToList", new[] { notGroupedType }, expr) as Expression;
|
var body = Expression.Call(typeof(Enumerable), methodName, new[] { notGroupedType }, expr) as Expression;
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotSupportedException($"unkown select type {selectType}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsGrouping(IQueryable query)
|
private static bool IsGrouping(IQueryable query)
|
||||||
{
|
{
|
||||||
// TODO needs to be alot better than this, but it will do for now.
|
// TODO needs to be alot better than this, but it will do for now.
|
||||||
|
@ -99,11 +99,13 @@ someQsomeQueryableOfTueryable.Count();
|
|||||||
|
|
||||||
### Select
|
### Select
|
||||||
|
|
||||||
|
> Note **PathToList** has been renamed to just **ToList** it seemed redudant, sorry for breaking change.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var querySelect = query.Select(t =>
|
var querySelect = query.Select(t =>
|
||||||
{
|
{
|
||||||
t.NullChecking(true); // not obligated but usefull for in memory queries.
|
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("FirstName");
|
||||||
t.Path("LastName", "ChangePropertyNameOfLastName");
|
t.Path("LastName", "ChangePropertyNameOfLastName");
|
||||||
});
|
});
|
||||||
@ -190,6 +192,8 @@ Assert.AreEqual(first?.FirstName, "David");
|
|||||||
|
|
||||||
### How it can be used in a web api
|
### 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
|
```csharp
|
||||||
[HttpGet][Route("FindClients")]
|
[HttpGet][Route("FindClients")]
|
||||||
public IHttpActionResult FindClients(string filterField = null, string filterValue = null,
|
public IHttpActionResult FindClients(string filterField = null, string filterValue = null,
|
||||||
|
Loading…
Reference in New Issue
Block a user