问题描述
我使用带有 MySql.EntityFrameworkCore 8.0.20 的 EF Core 3.1.1。由于服务已经上线,暂时无法更新包。
当添加如下一行时,DateTimeOffset.Now
被评估在生成 sql 查询之前,即将系统时区中的当前时间推送到数据库。 >
dbContext.Set<MyTable>().Add(new MyTable
{
...
RegisteredAt = DateTimeOffset.Now
...
});
但是,当通过比较 DateTimeOffset
值的查询检索行时,DateTimeOffset.Now
被替换为 UTC_TIMESTAMP()
,表示当前的 UTC 时间。我认为这应该是 CURRENT_TIMESTAMP()
(或 Now()
),因为 DateTimeOffset.Now
在其他上下文中被视为当前本地时间。
var myTable = from m in dbContext.Set<MyTable>()
where m.RegisteredAt < DateTimeOffset.Now
select m;
SELECT ...,`i`.`RegisteredAt`,...
FROM `Item` AS `i`
WHERE (`i`.`BeginsAt` < UTC_TIMESTAMP())
我发现将 DateTimeOffset.Now
移动到单独的变量可以解决这个问题,但这需要我使用 DateTimeOffset.Now
查找和编辑每个 LINQ 查询。
var currentTime = DateTimeOffset.Now;
var myTable = from m in dbContext.Set<MyTable>()
where m.RegisteredAt < currentTime
select m;
EF Core 3.1.1 中是否有任何功能可以拦截生成的 sql 并将 UTC_TIMESTAMP()
替换为 CURRENT_TIMESTAMP()
?
解决方法
我发现 EF Core 3 有一个名为 interceptors 的特性,它可以用于在执行之前改变所有 SQL 查询。覆盖 DbCommandInterceptor.ReaderExecuting
和 DbCommandInterceptor.ReaderExecutingAsync
并按如下方式编辑 SQL 查询:
public override InterceptionResult<DbDataReader>,ReaderExecuting(
DbCommand command,CommandEventData eventData,InterceptionResult<DbDataReader> result)
{
command.CommandText = command.CommandText.Replace("UTC_TIMESTAMP()","CURRENT_TIMESTAMP()");
return result;
}
// Do similarly in ReaderExecutingAsync
但我不确定这是否只会对性能产生有限的影响。