我正在尝试为按日期分组的自定义构建表达式树,对此进行转换:
groupedData = entity.GroupBy(e => new DateTime(e.created_date.Year, 1, 1));
进入一个无关源实体的扩展名。到目前为止,我有:
public static IQueryable<IGrouping<DateTime, TSource>> DateGroup<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, DateTime>> dateSelector, GraphDataTimeSpan span)
{
var year = Expression.Property(dateSelector.Body, nameof(DateTime.Year));
var ctorinfo = typeof(DateTime).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int) });
var ctroExp = Expression.New(ctorinfo, year, Expression.Constant(1), Expression.Constant(1));
var lambda = Expression.Lambda<Func<TSource, DateTime>>(ctroExp, dateSelector.Parameters);
switch (span)
{
case GraphDataTimeSpan.Yearly:
return source.GroupBy(lambda);
case GraphDataTimeSpan.Monthly:
break;
case GraphDataTimeSpan.Weekly:
break;
case GraphDataTimeSpan.Daily:
break;
}
return source.GroupBy(lambda);
}
但是它根本不起作用,抛出一个错误:
虽然我在C#交互式控制台上尝试时看起来还可以:
Expression.Lambda>(ctroExp,dateSelector.Parameters)
[test =>新的DateTime(test.Created.Year,1,1)] {正文= [新的DateTime(test.Created.Year,1,1)]
答案 0 :(得分:1)
我已将您的代码简化为:
public static IQueryable<IGrouping<DateTime, TSource>> DateGroup<TSource>(this IQueryable<TSource> source, Func<TSource, DateTime> dateSelector, GraphDataTimeSpan span)
{
switch (span)
{
case GraphDataTimeSpan.Yearly:
return source.GroupBy(e => new DateTime(dateSelector(e).Year,1,1));
case GraphDataTimeSpan.Monthly:
return source.GroupBy(e => new DateTime(dateSelector(e).Year,dateSelector(e).Month,1));
case GraphDataTimeSpan.Weekly:
// TO DO
break;
case GraphDataTimeSpan.Daily:
// TO DO
break;
}
return source.GroupBy(e => dateSelector(e));
}
使用此数据集:
List<Item> dates = new List<Item>{
new Item(new DateTime(1901,1,1)),
new Item(new DateTime(1902,1,1)),
new Item(new DateTime(1902,2,1)),
new Item(new DateTime(1903,4,1)),
new Item(new DateTime(1902,1,2)),
new Item(new DateTime(1905,1,3)),
new Item(new DateTime(1907,2,1))
};
以下
foreach(var d in dates.AsQueryable().DateGroup(e => e.Date, GraphDataTimeSpan.Yearly))
{
Console.WriteLine(d.Key.ToString("yyyy"));
foreach(var d2 in d)
Console.WriteLine(" |"+d2.Date.ToString("dd/MM/yyyy"));
}
给我:
1901
|01/01/1901
1902
|01/01/1902
|01/02/1902
|02/01/1902
1903
|01/04/1903
1905
|03/01/1905
1907
|01/02/1907
并且:
foreach(var d in dates.AsQueryable().DateGroup(e => e.Date, GraphDataTimeSpan.Monthly))
{
Console.WriteLine(d.Key.ToString("MM/yyyy"));
foreach(var d2 in d)
Console.WriteLine(" |"+d2.Date.ToString("dd/MM/yyyy"));
}
给我:
01/1901
|01/01/1901
01/1902
|01/01/1902
|02/01/1902
02/1902
|01/02/1902
04/1903
|01/04/1903
01/1905
|03/01/1905
02/1907
|01/02/1907
答案 1 :(得分:0)
我摆弄着类似的东西。 也许看看Linq generic GroupBy date and other fields at the same time
我使用了一个单独的类来存储分组密钥。
public class DateGroupKey
{
public int Year { get; set; }
public int Month { get; set; }
public int Week { get; set; }
public int Day { get; set; }
}
扩展方法如下:
public static IEnumerable<IGrouping<DateGroupKey, TValue>> GroupByDate<TValue>(
this IEnumerable<TValue> source,
Func<TValue, DateTime> dateSelector,
DateGroupType dateGroupType)
{
Func<TValue, DateGroupKey> keySelector = null;
switch (dateGroupType)
{
case DateGroupType.Year:
keySelector = val => new DateGroupKey { Year = dateSelector(val).Year };
break;
case DateGroupType.Month:
keySelector = val => new DateGroupKey { Year = dateSelector(val).Year, Month = dateSelector(val).Month };
break;
case DateGroupType.Week:
keySelector = val => new DateGroupKey { Year = dateSelector(val).Year, Week = dateSelector(val).GetIso8601WeekOfYear() };
break;
case DateGroupType.Day:
keySelector = val => new DateGroupKey { Year = dateSelector(val).Year, Month = dateSelector(val).Month, Day = dateSelector(val).Day };
break;
default:
throw new NotSupportedException($"Group type not supported: {dateGroupType}");
}
return source.GroupBy(keySelector, new DateGroupKeyComparer());
}
和相等比较器:
public class DateGroupKeyComparer : IEqualityComparer<DateGroupKey>
{
public bool Equals(DateGroupKey x, DateGroupKey y)
{
return x.Year == y.Year &&
x.Month == y.Month &&
x.Week == y.Week &&
x.Day == y.Day;
}
public int GetHashCode(DateGroupKey obj)
{
unchecked
{
var h = 0;
h = (h * 31) ^ obj.Year;
h = (h * 31) ^ obj.Month;
h = (h * 31) ^ obj.Week;
h = (h * 31) ^ obj.Day;
return h;
}
}
}
使用方式
var grouped = results.GroupByDate<ProductDto>(x => x.TimeStamp, DateGroupType.Month);