咨询区
Aza:
在 Entity Framework 6 中,我可以用 SqlFunctions.DatePart()
函数来实现,参考如下代码:
var byWeek = data.GroupBy(x => SqlFunctions.DatePart("week", x.Date));
现在的问题是, Entity Framework Core 中不提供如 DbFunctions
和 SqlFunctions
方法,这就很尴尬了,请问我该如何解决呢?
回答区
cyptus
既然没有现成的函数,可以自己实现一个,将 sql 中的 datepart
方法用 C# 中的 DbFunctionAttribute 给标注上,这样做的好处是告诉 efcore 不要去以 string 方式处理 detepart 参数,参考代码如下:
DbContext:
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));
更多信息参考 github:https://github.com/aspnet/EntityFrameworkCore/issues/10404
Nikolay Kostov:
确实有些麻烦,我现在的变通方法是除7实现,首先自定义个方法,代码如下:
private DateTime GetFirstMondayOfYear(int year)
{var dt = new DateTime(year, 1, 1);while (dt.DayOfWeek != DayOfWeek.Monday){dt = dt.AddDays(1);}return dt;
}
然后在分组的时候计算。
var firstMondayOfYear = this.GetFirstMondayOfYear(DateTime.Now.Year);var entries = this.entitiesService.FindForLastMonths(this.CurrentUser.Id, 6).GroupBy(x => ((int)(x.Date - firstMondayOfYear).TotalDays / 7))
这个分组会得到当前年的周个数,负值是表示挂在前一年的, 之后就可以通过下面的属性方法得到当前的周名称。
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}";}
}
点评区
sql处理稍微复杂一点,用ef处理起来还是有些麻烦的,没啥好说的,学习了。