EF Core 中的 SqlFunctions.DatePart 等效项
Posted
技术标签:
【中文标题】EF Core 中的 SqlFunctions.DatePart 等效项【英文标题】:SqlFunctions.DatePart equivalent in EF Core 【发布时间】:2019-03-02 22:10:23 【问题描述】:EF Core 中以下语句的等价物是什么?
SqlFunctions.DatePart("week", x.MyDate)
EF.Functions
似乎没有DatePart
方法。
【问题讨论】:
SqlFunctions.DatePart("week", x.MyDate)
返回什么?
SqlFunctions 在 .NET Core 中不存在。
没有直接的办法,但是你可以试试 DateTime inputDate = DateTime.Parse(date.Trim()); CultureInfo cul = CultureInfo.CurrentCulture; int weekNum = cul.Calendar.GetWeekOfYear(inputDate, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
Week 正是 .net 的 DateTime
所没有的一件事。所有其他 DateTime“部分”属性,如 Year
,都被转换为 SQL 的 DATEPART
函数。但我想这就是你问“周”的原因。
【参考方案1】:
可以通过使用 DbFunctionAttribute 包装 datepart SQL 函数来使用它。 棘手的部分是告诉 ef core 不要将 datepart 类型参数作为字符串处理。示例:
DbContextef core <= 2.1
:
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]
));
DbContext ef core >= 3.1
(静态 SqlFunctionExpression.Create
调用而不是 ctor):
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 => SqlFunctionExpression.Create(nameof(DatePart), new[]
new SqlFragmentExpression(args.ToArray()[0].ToString()),
args.ToArray()[1]
, typeof(int?), null));
查询:
repository.Where(x => dbContext.DatePart("week", x.CreatedAt) > 10);
更多信息:https://github.com/aspnet/EntityFrameworkCore/issues/10404
注意不要在 DbContext 的接口上调用 DbFunction 方法。调用必须直接在 DbContext 实例上发生。
编辑:对于ef core 3.1
,您可以使用静态方法SqlFunctionExpression.Create
而不是ctor:
【讨论】:
无法创建SqlFragmentExpression实例,构造函数是内部O_o 已修复:github.com/aspnet/EntityFrameworkCore/pull/18208 哦,我明白了,谢谢。我想除了这个之外没有其他方法可以做到这一点,对吧?有没有人致力于添加这些功能? 新的 SqlFragmentExpression(args.ToArray()[0].ToString()) 结果为 [Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlConstantExpression]【参考方案2】:对于 EF Core 5,它甚至有所不同,因为 SqlFunctionExpression.Create
工厂现在已过时,应该改用 SqlFunctionExpression
构造。这是更新后的代码(如果将其添加到数据库上下文中):
public partial class ApplicationDbContext : DbContext
public int? DatePart(string datePartArg, DateTimeOffset? date) => throw new InvalidOperationException($"nameof(DatePart) cannot be called client side.");
protected override void OnModelCreating(ModelBuilder builder)
var methodInfo = typeof(DbFunctionExtensions).GetMethod(nameof(DatePart));
var datePartMethodInfo = typeof(ApplicationDbContext) // Your DB Context
.GetRuntimeMethod(nameof(ApplicationDbContext.DatePart), new[] typeof(string), typeof(DateTimeOffset) );
builder.HasDbFunction(datePartMethodInfo)
.HasTranslation(args =>
new SqlFunctionExpression("DATEPART",
new[]
new SqlFragmentExpression((args.ToArray()[0] as SqlConstantExpression).Value.ToString()),
args.ToArray()[1]
,
true,
new[] false, false ,
typeof(int?),
null
)
);
注意:您可以根据需要切换到DateTime
而不是DateTimeOffset
。
(该异常与 EF Core 5 无关,对于稍后处理代码或尝试调用方法客户端的任何人来说更清楚)。
【讨论】:
【参考方案3】:对于 ef core 3.1 的解决方案略有不同,应先将参数转换为 SqlConstantExpression
,然后将其 Value
传递给 SqlFragmentExpression
构造函数:
public static class DbFunctionExtensions
public static int? DatePart(string type, DateTime? date) => throw new Exception();
public static void ConfigureDbFunctions(this ModelBuilder modelBuilder)
var mi = typeof(DbFunctionExtensions).GetMethod(nameof(DatePart));
modelBuilder.HasDbFunction(mi, b => b.HasTranslation(e =>
var ea = e.ToArray();
var args = new[]
new SqlFragmentExpression((ea[0] as SqlConstantExpression).Value.ToString()),
ea[1]
;
return SqlFunctionExpression.Create(nameof(DatePart), args, typeof(int?), null);
));
【讨论】:
嗨@Gene-R,我正在尝试使用 EF Core 3.1 让它工作。我可以拨打电话,但遇到无法翻译的错误。我在其中使用 ...“DbFunctionExtensions.DatePart("w", a.ReferenceDate) ==2" 调用上述内容。非常感谢任何帮助 不应该是DbFunctionExtensions.DatePart("week", a.ReferenceDate)
吗?我也在使用 datepart 之前检查 NULL 列以上是关于EF Core 中的 SqlFunctions.DatePart 等效项的主要内容,如果未能解决你的问题,请参考以下文章
EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?
EF Core 中的 SqlFunctions.DatePart 等效项