如何使用 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__17
2.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
, ToDouble
、ToInt16
、ToInt32
、ToInt64
和 ToString
。
这意味着没有与数据库无关的方式来执行服务器端转换。
由于您似乎正在使用 SqlServer,作为解决方法,我建议使用 implicit 数据转换(目前由 SqlServer 提供程序支持),方法是使用 "double cast" 技术我对 的回答,例如
.Where(t1 => (DateTime)(object)JsonExtensions.JsonValue(t1.SampleJson, "$.samplePath.sampleDate") >= date);
(object)
cast 用于避免 C# 编译器错误。在查询翻译过程中,这两种转换都将被删除,SQL 服务器隐式数据转换最终将完成这项工作。
我正在使用 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.WhereEnumerableIterator
1.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__17
2.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
, ToDouble
、ToInt16
、ToInt32
、ToInt64
和 ToString
。
这意味着没有与数据库无关的方式来执行服务器端转换。
由于您似乎正在使用 SqlServer,作为解决方法,我建议使用 implicit 数据转换(目前由 SqlServer 提供程序支持),方法是使用 "double cast" 技术我对
.Where(t1 => (DateTime)(object)JsonExtensions.JsonValue(t1.SampleJson, "$.samplePath.sampleDate") >= date);
(object)
cast 用于避免 C# 编译器错误。在查询翻译过程中,这两种转换都将被删除,SQL 服务器隐式数据转换最终将完成这项工作。