TSQL-запрос CAST к int + 1 к LINQ - PullRequest
0 голосов
/ 16 ноября 2018

Я ломаю голову над следующим запросом linq to sql. Идея состоит в том, чтобы получить наименьшее следующее целое число по сравнению со всеми элементами REG_CODE. Это поле (REG_CODE) является полем varchar (10). Я пытаюсь преобразовать следующий tsql в linq-to-entity (EF 6.0):

SELECT TOP 1 CAST( [Extent1].[REG_CODE] AS int) + 1 
    FROM [dbo].[Notifications] [Extent1]
WHERE NOT ([Extent1].[REG_CODE] LIKE N'%~[a-z]%' ESCAPE N'~') AND (1 = (ISNUMERIC([Extent1].[REG_CODE]))) AND
      NOT EXISTS(SELECT * FROM [dbo].[Notifications] t2 WHERE CAST( t2.REG_CODE AS int) = CAST( [Extent1].[REG_CODE] AS int) + 1 )
ORDER BY [Extent1].[REG_CODE]

(обратите внимание на +1, я хочу следующую часть) Дизайн не такой уж и крутой. Поле [REG_CODE] должно быть целочисленным, но это не так и не будет в ближайшее время.

Это:

float notificationMaxRegCodeNumeric =
    db.Notifications.Where(not => not.Reg_Code != null && !not.Reg_Code.Contains("[a-z]") && SqlFunctions.IsNumeric(not.Reg_Code) == 1)
        .OrderByDescending(not => not.Reg_Code)
        .Select(not => not.Reg_Code)
        .Cast<int>()
        .Max();

Успешно преобразуется в:

SELECT MAX(CAST( [Extent1].[REG_CODE] AS int)) AS[A1]
FROM[dbo].[Notifications] AS[Extent1]
WHERE ([Extent1].[REG_CODE] IS NOT NULL) AND(NOT([Extent1].[REG_CODE] LIKE N'%~[a-z]%' ESCAPE N'~')) AND(1 = (ISNUMERIC([Extent1].[REG_CODE])))

Пока у меня есть:

int nextNotificationMaxRegCodeNumericInt = db.Notifications.Where(not =>
    not.Reg_Code != null && !not.Reg_Code.Contains("[a-z]") &&
    SqlFunctions.IsNumeric(not.Reg_Code) == 1 &&
    db.Notifications.Any(klainternal => not.Reg_Code.Cast<int>() == klainternal.Reg_Code.Cast<int>())
    )
.OrderByDescending(not => not.Reg_Code)
.Select(not => not.Reg_Code)
.Cast<int>();

но бросает:

DbExpressionBinding требует входное выражение с коллекцией ResultType`.

Также Convert.ToInt32() бросает:

linq для сущностей не распознает метод 'int32 toint32 (system.string)' метод`

(.Max() на самом деле не имеет отношения к тому, что я ищу, но это рабочая часть запроса)

Есть предложения?

1 Ответ

0 голосов
/ 17 ноября 2018

Во-первых, поздравляем с обнаружением трюка Cast<T>()!Похоже, это единственный готовый EF6 способ приведения string к чему-либо еще - все другие попытки, такие как (int)(object)stringValue или Convert.ToInt32(stringValue), просто блокируются как не поддерживаемые.

Но обратите внимание, что *Метод 1007 * определен для IEnumerable и IQueryable, а результат равен соответственно IEnumerable<T> и IQueryable<T>, т.е. работает с последовательностью и создает последовательность.Он появляется на string, потому что string - это IEnumerable<char>, то есть IEnumerable, но это не то, что нам нужно.

Так что хитрость заключается в том, чтобы всегда использовать проекцию (Select) + Castделать преобразования.Применение его к вашему запросу приводит к чему-то вроде этого:

int nextNotificationMaxRegCodeNumericInt = db.Notifications
    .Where(n => n.Reg_Code != null &&
        !n.Reg_Code.Contains("[a-z]") &&
        SqlFunctions.IsNumeric(n.Reg_Code) == 1)
    .Select(n => n.Reg_Code).Cast<int>() // <--
    .Select(reg_Code => reg_Code + 1)
    .Where(reg_Code => !db.Notifications.Select(n => n.Reg_Code).Cast<int>() // <--
        .Contains(reg_Code))
    .OrderByDescending(reg_Code => reg_Code)
    .FirstOrDefault();

, который преобразуется в

SELECT TOP (1)
    [Project1].[C1] AS [C1]
    FROM ( SELECT
         CAST( [Extent1].[Reg_Code] AS int) + 1 AS [C1]
        FROM [dbo].[Notifications] AS [Extent1]
        WHERE ([Extent1].[Reg_Code] IS NOT NULL) AND ( NOT ([Extent1].[Reg_Code] LIKE N'%~[a-z]%' ESCAPE N'~')) AND (1 = (ISNUMERIC([Extent1].[Reg_Code])))
    )  AS [Project1]
    WHERE  NOT EXISTS (SELECT
        1 AS [C1]
        FROM [dbo].[Notifications] AS [Extent2]
        WHERE  CAST( [Extent2].[Reg_Code] AS int) = [Project1].[C1]
    )
    ORDER BY [Project1].[C1] DESC
...