如何使用 EF Core 2.2 将 JSON_VALUE 转换为 DateTime?

How can a JSON_VALUE be converted to a DateTime with EF Core 2.2?

我正在使用 How to write DbFunction's translation 中的技术映射 JSON_VALUE。由于并非 JSON 中的所有值都是字符串,因此有时需要进行转换。

转换为int时,一切正常:

var results = context.Set<SampleTable>()
    .Where(t1 => Convert.ToInt32(
        JsonExtensions.JsonValue(t1.SampleJson, "$.samplePath.sampleInt")) > 1);
    .ToList();

结果 SQL 是:

SELECT *
FROM [SampleTable] AS [t1]
WHERE (CONVERT(int, JSON_VALUE([t1].[SampleJson], N'$.samplePath.sampleInt')) > 1)

但是,当转换为 DateTime 时,它不起作用:

DateTime date = new DateTime(2019, 6, 1);
var results = context.Set<SampleTable>()
    .Where(t1 => Convert.ToDateTime(
        JsonExtensions.JsonValue(t1.SampleJson, "$.samplePath.sampleDate")) >= date);
    .ToList();

没有被映射,而是直接调用了JsonValue,这导致了以下异常:

System.NotSupportedException HResult=0x80131515 Message=Specified method is not supported. StackTrace: at JsonExtensions.JsonValue(String column, String path) at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__172.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()

为什么 DateTime 的行为与 int 不同?我该怎么做才能使 DateTime 正常工作?

问题是并非所有 Convert 方法都受支持。

事实上 none 标准 支持 - EF Core 允许 database providers to add CLR method and member translators for whatever they like. For instance SqlServer provider currently supports ToByte, ToDecimal, ToDoubleToInt16ToInt32ToInt64ToString

这意味着没有与数据库无关的方式来执行服务器端转换。

由于您似乎正在使用 SqlServer,作为解决方法,我建议使用 implicit 数据转换(目前由 SqlServer 提供程序支持),方法是使用 "double cast" 技术我对 的回答,例如

.Where(t1 => (DateTime)(object)JsonExtensions.JsonValue(t1.SampleJson, "$.samplePath.sampleDate") >= date);

(object) cast 用于避免 C# 编译器错误。在查询翻译过程中,这两种转换都将被删除,SQL 服务器隐式数据转换最终将完成这项工作。