【问题标题】:How can a JSON_VALUE be converted to a DateTime with EF Core 2.2?如何使用 EF Core 2.2 将 JSON_VALUE 转换为 DateTime?
【发布时间】:2019-10-23 04:12:18
【问题描述】:

我正在使用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 H结果=0x80131515 Message=不支持指定的方法。 堆栈跟踪: 在 JsonExtensions.JsonValue(字符串列,字符串路径) 在 System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__172.MoveNext() 在 Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()

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

【问题讨论】:

    标签: c# json sql-server entity-framework-core ef-core-2.2


    【解决方案1】:

    问题是不是所有的Convert方法都支持。

    事实上,它们都标准受支持 - EF Core 允许 database providers 添加 CLR 方法和成员翻译器以供他们喜欢。例如 SqlServer 提供程序currently supportsToByteToDecimalToDoubleToInt16ToInt32ToInt64ToString

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

    由于您似乎在使用 SqlServer,作为解决方法,我可以建议通过使用我对 @987654323 的回答中的“双重转换”技术来利用 implicit 数据转换(目前由 SqlServer 提供程序支持) @,例如

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

    (object) cast 用于避免 C# 编译器错误。在查询转换期间,两个强制转换都将被删除,SQL Server 隐式数据转换最终将完成这项工作。

    【讨论】:

    • 请注意,没有隐式转换。这将是 SQL Server 上字符串比较的字符串,因为 JSON_VALUE 返回一个字符串,而 EF Core 会将 c# DateTime 呈现为字符串。如果所有 JSON 日期的格式都与 DateTime2FormatConst 兼容,这将非常有效。
    • @RichBennema 我很确定date 变量将被绑定为datetimedatetime2 SQL 参数,所以应该有一个转换。
    • 是的,你是对的。这是通过 SQL Server Profiler 发出的命令:exec sp_executesql N'SELECT * FROM [SampleTable] AS [t1] WHERE (JSON_VALUE([t1].[SampleJson], N''$.samplePath.sampleDate'') &gt;= @__date_0)',N'@__date_0 datetime2(7)',@__date_0='2019-06-01 00:00:00'。在测试中,我在来回更新一些日期的格式后确认了一致的结果。
    猜你喜欢
    • 2020-07-13
    • 2020-03-13
    • 2017-06-22
    • 2020-04-24
    • 2019-12-14
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    • 2020-03-04
    相关资源
    最近更新 更多