【问题标题】:How to group by week in Entity Framework Core?如何在 Entity Framework Core 中按周分组?
【发布时间】:2017-07-29 05:54:48
【问题描述】:

在 Entity Framework 6 中我可以使用SqlFunctions.DatePart() 方法:

var byWeek = data.GroupBy(x => SqlFunctions.DatePart("week", x.Date));

但是这些类(DbFunctionsSqlFunctions 在 Entity Framework Core 中不可用)(reference)。

所以我的问题是如何在 Entity Framework 核心中按周分组?

【问题讨论】:

  • 由于目前所有具有 GroupBy 子句的 EF Core 查询都在内存中处理,因此您可以安全地使用 x.Date.DayOfYear / 7 或类似的东西。
  • @IvanStoev 不再。自 ef core 2.1 起,group-by 查询被编译为 sql。请参阅我的答案以获取工作示例。
  • 注意:对于发现此问题的任何人,请确保您了解 week 和 iso_week 之间的区别以及您想要的。 ISO 周的年份并不总是与日历年相同(例如,在 2020 年,第 1 周开始于 2010 年 12 月 30 日)。 en.wikipedia.org/wiki/ISO_week_date

标签: linq group-by .net-core entity-framework-core week-number


【解决方案1】:

我目前缺少功能的解决方法是

var firstMondayOfYear = this.GetFirstMondayOfYear(DateTime.Now.Year);
var entries =
    this.entitiesService.FindForLastMonths(this.CurrentUser.Id, 6)
        .GroupBy(x => ((int)(x.Date - firstMondayOfYear).TotalDays / 7))

函数GetFirstMondayOfYear

private DateTime GetFirstMondayOfYear(int year)
{
    var dt = new DateTime(year, 1, 1);
    while (dt.DayOfWeek != DayOfWeek.Monday)
    {
        dt = dt.AddDays(1);
    }

    return dt;
}

这个分组给出了当前年份的周数和前几年的负值。

稍后您可以使用此 getter 获取周名称:

public string WeekName
{
    get
    {
        var year = DateTime.Now.AddYears((int)Math.Floor(this.WeekNumber / 52.0)).Year;
        var weekNumber = this.WeekNumber % 52;
        while (weekNumber < 0)
        {
            weekNumber += 52;
        }

        return $"{year}, W{weekNumber}";
    }
}

【讨论】:

  • 请注意,整个查询将在内存中完成,因此可能会非常慢。
【解决方案2】:

可以通过使用 DbFunctionAttribute 包装 datepart SQL 函数来使用它。 棘手的部分是告诉 ef core 不要将 datepart 类型参数作为字符串处理。示例:

数据库上下文:

public int? DatePart(string datePartArg, DateTime? date) => throw new Exception();

public void OnModelCreating(DbModelBuilder modelBuilder) {
    var methodInfo = typeof(DbContext).GetRuntimeMethod(nameof(DatePart), new[] { typeof(string), typeof(DateTime) });
    modelBuilder
        .HasDbFunction(methodInfo)
        .HasTranslation(args => new SqlFunctionExpression(nameof(DatePart), typeof(int?), new[]
                {
                        new SqlFragmentExpression(args.ToArray()[0].ToString()),
                        args.ToArray()[1]
                }));
}

查询:

repository.GroupBy(x => dbContext.DatePart("week", x.CreatedAt));

更多信息:https://github.com/aspnet/EntityFrameworkCore/issues/10404

【讨论】:

    【解决方案3】:

    我碰巧已经在使用一个视图,所以我只是在该视图中添加了额外的列,表示周、月和年 - 以便通过 EF Core 进行分组。

    OrderDateDt,
    DATEPART(week, OrderDateDt) OrderDateDt_Week,
    DATEPART(month, OrderDateDt) OrderDateDt_Month,
    DATEPART(year, OrderDateDt) OrderDateDt_Year,
    

    【讨论】:

    • 请注意 datepart(week) 不能用于索引视图,但我认为 datepart(iso_week) 可以。
    • 自从我回答了这个问题后,我对 ISO_WEEK 的了解比我关心的要多 - 所以一定要看看哪个适合你的需要。今天(2019 年 12 月 30 日)的 ISO_WEEK 实际上是 1,因为它是明年第一周的一部分 - 所以你不能使用 year 否则你最终会在 19 年 12 月 30 日成为第一周2019 年,这是不对的!
    猜你喜欢
    • 2021-03-08
    • 2020-07-21
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 2017-12-22
    相关资源
    最近更新 更多