【问题标题】:TSQL query CAST to int + 1 to LINQTSQL 查询 CAST 到 int + 1 到 LINQ
【发布时间】:2018-11-16 14:43:11
【问题描述】:

我正在为以下 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 to entity 无法识别方法 'int32 toint32(system.string)' 方法`

.Max() 与我要查找的内容并不真正相关,它在查询的工作部分中)

有什么建议吗?

【问题讨论】:

  • 我认为不需要使用 c# 将字段转换为整数,因为它应该已经被定义为这样,不是吗?
  • Cast 是一种 Linq 方法,它将强制转换集合中的所有值,而不是单个值(我怀疑即使正确使用它也会转换为 SQL)。您需要一个设置为转换为所需 SQL 的方法。我不相信有什么内置的,但看看这个关于如何创建你自己的问题stackoverflow.com/questions/5971521/…
  • @user1666620 REG_CODE 字段是一个 varchar(10) 字段,因此与所有 REG_CODE 项相比,我需要最小的下一个整数
  • 当您尝试执行数字顺序时,ORDER BY REG_CODE 的 SQL 是否危险,或者REG_CODE 是否包含前导零?
  • 你能用Convert.ToInt32显示代码吗?这是 LINQ to Entities 的正确方法 - 您使用的是什么版本的 EF?你在使用 EF Core 吗?

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


【解决方案1】:

首先,恭喜您找到Cast&lt;T&gt;() 技巧!这似乎是 EF6 将 string 转换为其他东西的唯一开箱即用方式 - 所有其他尝试(如 (int)(object)stringValueConvert.ToInt32(stringValue))都被简单地阻止,因为不受支持。

但请注意Cast&lt;T&gt;() 方法是为IEnumerableIQueryable 定义的,结果分别为IEnumerable&lt;T&gt;IQueryable&lt;T&gt;,即作用于序列并产生序列。它出现在string 上是因为stringIEnumerable&lt;char&gt;,因此是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

【讨论】:

  • 这就是我想要的!还有一件事是:ORDER BY [Project1].[C1] DESC,这必须没有 DESC,然后它得到下一个不存在的最大 REG_CODE。谢谢!
猜你喜欢
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多