Как преобразовать JSON_VALUE в DateTime с помощью EF Core 2.2? - PullRequest
1 голос
/ 07 июня 2019

Я отображаю JSON_VALUE, используя технику из Как написать перевод DbFunction .Поскольку не все значения в 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 Сообщение = Указанный метод не поддерживается.StackTrace: в JsonExtensions.JsonValue (столбец String, путь String) в System.Linq.Enumerable.WhereEnumerableIterator 1.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__17 2.MoveNext () в Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInext.ExceptionInteroror1.1.1022 *

Почему DateTime ведет себя не так, как int?Что я могу сделать, чтобы DateTime работал правильно?

1 Ответ

2 голосов
/ 09 июня 2019

Проблема в том, что поддерживаются не все Convert методы.

На самом деле ни один из них стандартно не поддерживается - EF Core позволяет поставщикам баз данных добавлять метод CLR и трансляторы членов для всего, что им нравится. Например, поставщик SqlServer в настоящее время поддерживает ToByte, ToDecimal, ToDouble, ToInt16, ToInt32, ToInt64 и ToString.

Это означает, что не существует независимого от базы данных способа выполнения преобразований на стороне сервера.

Поскольку вы, похоже, используете SqlServer, в качестве обходного пути я мог бы предложить использовать неявное преобразование данных (в настоящее время поддерживаемое поставщиком SqlServer) с использованием метода "двойного приведения" из моего ответа на аналогичный пост , например

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

(object) cast используется, чтобы избежать ошибки компилятора C #. Во время преобразования запроса оба приведения будут удалены, и неявное преобразование данных SQL Server в конечном итоге выполнит эту работу.

...