Как разобрать int в EF Core 3 Query? - PullRequest
0 голосов
/ 03 марта 2020

При обновлении до EF Core 3 я получаю следующую ошибку в следующем коде:

System.InvalidOperationException: 'выражение LINQ' DbSet .Max (c => Convert. ToInt32 (c .ClaimNumber.Substring (c .ClaimNumber.Length - 6))) 'не может быть переведено. Либо переписать запрос в форме, которую можно перевести, либо явно переключиться на оценку клиента, вставив вызов либо AsEnumerable (), AsAsyncEnumerable (), ToList (), либо ToListAsyn c (). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации. '

var maxId = Db.Claims
    .Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
    .Max(x => Convert.ToInt32(x));

Я также попытался использовать int.Parse вместо Convert.ToInt32, и он выдает ту же ошибку. Я понимаю сообщение об ошибке. Тем не менее, просто заставить SQL Server проанализировать строку в int в T- SQL с помощью CAST или CONVERT, я надеюсь, что есть простой способ написать запрос так, чтобы он преобразовался в правильную операцию на стороне сервера. ?

ОБНОВЛЕНИЕ После отличного ответа Клаудио я подумал, что должен добавить информацию для следующего человека, который придет. Я полагал, что причиной разбора была проблема с приведенным выше кодом, потому что следующее выполняется без ошибок и дает правильный результат:

var maxId = Db.Claims
    .Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
    .AsEnumerable()
    .Max(x => int.Parse(x));

Однако, я копнул глубже и обнаружил, что это запрос SQL EF выполняет из этого кода:

SELECT [c].[ClaimNumber], CAST(LEN([c].[ClaimNumber]) AS int) - 6
FROM [Claims] AS [c]
WHERE [c].[ClaimNumber] IS NOT NULL

То есть явно не делает ничего, как я хотел, и поэтому Клаудио прав, что вызов Substring на самом деле , проблема.

1 Ответ

2 голосов
/ 03 марта 2020

Отказ от ответственности: хотя это выполнимо, я настоятельно рекомендую вам не использовать преобразование типов в запросе, поскольку это приводит к значительному снижению производительности запроса.

Фактом является то, что Convert.ToInt(x) часть не является проблема здесь. Это c.ClaimsNumber.Substring(c.ClaimNumber.Length - 6), что переводчик EF Core не может переводить в T- SQL.

Несмотря на то, что функция RIGHT существует на Sql сервере, вы также не сможете используйте его с текущими версиями EF Core (последняя версия 3.1.2 на данный момент я пишу). Единственное решение, чтобы получить то, что вам нужно, - это создать пользовательскую функцию Sql Server, сопоставить ее с EF Core и использовать в своем запросе.

1) Создать функцию с помощью миграции

> dotnet ef migrations add CreateRightFunction

Во вновь созданный файл миграции поместите этот код:

public partial class CreateRightFunctions : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(@"
CREATE FUNCTION fn_Right(@input nvarchar(4000), @howMany int)
RETURNS nvarchar(4000)
BEGIN
RETURN RIGHT(@input, @howMany)
END
");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(@"
DROP FUNCTION fn_Right
");
    }
}

Затем запустите обновление базы данных:

dotnet ef database update

2) Сопоставить функцию с контекстом EF Core

В вашем контексте класса [DbFunction ("fn_Right")]

public static string Right(string input, int howMany)
{
    throw new NotImplementedException(); // this code doesn't get executed; the call is passed through to the database function
}

3) Используйте функцию в вашем запросе

var maxId = Db.Claims.Select(c => MyContext.Right(c.ClaimNumber, 6)).Max(x => Convert.ToInt32(x));

Сгенерированный запрос:

SELECT MAX(CONVERT(int, [dbo].[fn_Right]([c].[ClaimNumber], 6)))
FROM [Claims] AS [c]

Опять же, это далеко не лучшая практика, я думаю, вам следует подумать о добавлении столбца int в таблицу для хранения этого "числа", независимо от того, что оно представляет в вашем домене.

Кроме того, впервые 6 последних символов ClaimNumber содержат не-ди git символ, это больше не будет работать. Если ClaimNumber вводится человеком, рано или поздно это произойдет.

Вам следует создать код и спроектировать базу данных и приложение для надежности, даже если вы уверены, что эти 6 символов всегда будут представлять число , Они не могли делать это вечно:)

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