如何在 Entity Framework Core 中按周分组?
How to group by week in Entity Framework Core?
在Entity Framework6中我可以使用SqlFunctions.DatePart()
方法:
var byWeek = data.GroupBy(x => SqlFunctions.DatePart("week", x.Date));
但是这些类(DbFunctions
和SqlFunctions
在Entity Framework Core中不可用)(reference)。
所以我的问题是 如何在 Entity Framework 核心中按周分组?
我目前针对缺失功能的解决方法是
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}";
}
}
可以通过使用 DbFunctionAttribute 包装来使用 datepart SQL 函数。
棘手的部分是告诉 ef 核心不要将 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
我碰巧已经在使用一个视图,所以我只是向该视图添加了额外的列来表示周、月和年 - 以便通过 EF Core 轻松分组。
OrderDateDt,
DATEPART(week, OrderDateDt) OrderDateDt_Week,
DATEPART(month, OrderDateDt) OrderDateDt_Month,
DATEPART(year, OrderDateDt) OrderDateDt_Year,
在Entity Framework6中我可以使用SqlFunctions.DatePart()
方法:
var byWeek = data.GroupBy(x => SqlFunctions.DatePart("week", x.Date));
但是这些类(DbFunctions
和SqlFunctions
在Entity Framework Core中不可用)(reference)。
所以我的问题是 如何在 Entity Framework 核心中按周分组?
我目前针对缺失功能的解决方法是
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}";
}
}
可以通过使用 DbFunctionAttribute 包装来使用 datepart SQL 函数。 棘手的部分是告诉 ef 核心不要将 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
我碰巧已经在使用一个视图,所以我只是向该视图添加了额外的列来表示周、月和年 - 以便通过 EF Core 轻松分组。
OrderDateDt,
DATEPART(week, OrderDateDt) OrderDateDt_Week,
DATEPART(month, OrderDateDt) OrderDateDt_Month,
DATEPART(year, OrderDateDt) OrderDateDt_Year,