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
(在您的用法中)be
GroupByDate
?是的,抱歉。编辑了我的答案。不,我意识到。可以转换为表达式,但我不确定如何告诉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);