TSQL查询CAST为int +1为LINQ

时间:2018-11-16 14:43:11

标签: c# entity-framework linq linq-to-entities expression-trees

我正在为下面的linq to sql查询而绞尽脑汁。与所有REG_CODE项相比,此想法是获得最小的下一个整数。该字段(REG_CODE)是varchar(10)字段。 我正在尝试将以下tsql转换为linq-to-entities(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 :(得分:3)

首先,祝贺您找到了Cast<T>()的把戏!看来这是将string投射到其他对象的唯一开箱即用的EF6方法-像(int)(object)stringValueConvert.ToInt32(stringValue)之类的所有其他尝试都被简单地阻止为不支持。

但是请注意,Cast<T>()方法是为IEnumerableIQueryable定义的,结果分别是IEnumerable<T>IQueryable<T>,即按顺序工作并产生顺序。之所以出现在string上是因为stringIEnumerable<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