C# 为日期分组(GroupBy)创建Linq到实体IQueryable扩展
我正在尝试按日期为自定义分组构建表达式树,请转换以下内容:C# 为日期分组(GroupBy)创建Linq到实体IQueryable扩展,c#,linq,linq-to-entities,linq-expressions,C#,Linq,Linq To Entities,Linq Expressions,我正在尝试按日期为自定义分组构建表达式树,请转换以下内容: groupedData = entity.GroupBy(e => new DateTime(e.created_date.Year, 1, 1)); 进入一个不关心源实体是什么的扩展。到目前为止,我已经: public static IQueryable<IGrouping<DateTime, TSource>> DateGroup<TSource>(this IQueryable<T
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);
}
public静态IQueryable日期组(此IQueryable源、表达式日期选择器、GraphDataTimeSpan)
{
var year=Expression.Property(dateSelector.Body,nameof(DateTime.year));
var ctorinfo=typeof(DateTime).GetConstructor(新类型[]{typeof(int),typeof(int),typeof(int)});
var ctroExp=Expression.New(ctorinfo,year,Expression.Constant(1),Expression.Constant(1));
var lambda=Expression.lambda(ctroExp,dateSelector.Parameters);
开关(span)
{
案例图数据时间跨度年度:
返回source.GroupBy(lambda);
案例图DataTimeSpan.每月:
打破
案例图DataTimeSpan.每周:
打破
案例图DataTimeSpan.每日:
打破
}
返回source.GroupBy(lambda);
}
但它根本不起作用,抛出了一个错误:
虽然我在C#交互式控制台上试用时看起来还不错:
Expression.Lambda>(ctroExp,dateSelector.Parameters)
[test=>newdatetime(test.Created.Year,1,1)]{Body=[newdatetime(test.Created.Year,1,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));
}
给我:
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
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
以及:
给我:
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
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
我胡乱摆弄着类似的东西。 也许你可以看看 我使用了一个单独的类来存储分组键
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());
}
公共静态IEnumerable GroupByDate(
这是一个数不清的来源,
Func日期选择器,
DateGroupType(日期组类型)
{
Func keySelector=null;
开关(dateGroupType)
{
案例日期组类型。年份:
keySelector=val=>newdategroupkey{Year=dateSelector(val).Year};
打破
案例日期组类型。月份:
keySelector=val=>newdategroupkey{Year=dateSelector(val).Year,Month=dateSelector(val).Month};
打破
案例日期组类型。周:
keySelector=val=>new DateGroupKey{Year=dateSelector(val).Year,Week=dateSelector(val).GetIso8601WeekOfYear()};
打破
案例日期组类型。日期:
keySelector=val=>newdategroupkey{Year=dateSelector(val).Year,Month=dateSelector(val).Month,Day=dateSelector(val.Day};
打破
违约:
抛出新的NotSupportedException($“组类型不受支持:{dateGroupType}”);
}
返回source.GroupBy(keySelector,newDateGroupKeyComparer());
}
和相等比较器:
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;
}
}
}
公共类DateGroupKeyComparer:IEqualityComparer
{
public bool Equals(DateGroupKey x,DateGroupKey y)
{
收益x.年==y.年&&
x、 月份==y.月份&&
x、 周==y.周&&
x、 日==y.日;
}
public int GetHashCode(DateGroupKey obj)
{
未经检查
{
var h=0;
h=(h*31)^目标年;
h=(h*31)^obj.月;
h=(h*31)^obj.周;
h=(h*31)^obj.日;
返回h;
}
}
}
像这样使用它
var grouped = results.GroupByDate<ProductDto>(x => x.TimeStamp, DateGroupType.Month);
var group=results.GroupByDate(x=>x.TimeStamp,DateGroupType.Month);
如何调用此扩展名?例如entity.DateGroup(e=>e.created\u date,GraphDataTimeSpan.Yearly)
?是的,这将是上下文的一部分。Where().DateGroup().ToList()不应GroupBy
(在您的用法中)beGroupByDate
?是的,抱歉。编辑了我的答案。不,我意识到。可以转换为表达式,但我不确定如何告诉EF如何将其转换为SQL代码。不起作用,因为函数没有转换为SQL,错误:方法'System.Object DynamicInvoke(System.Object[])'不支持转换为SQL。此时我没有数据。Yet可能会同时出现dateSelector(e)
和dateSelector。调用(e)
会导致相同的错误?我目前无法用SQL测试它
var grouped = results.GroupByDate<ProductDto>(x => x.TimeStamp, DateGroupType.Month);