代码之家  ›  专栏  ›  技术社区  ›  pbristow

如何在efcore3查询中解析int?

  •  0
  • pbristow  · 技术社区  · 4 年前

    System.InvalidOperationException:'LINQ表达式'DbSet .Max(c=>Convert.ToInt32(c.ClaimNumber.Substring(c.ClaimNumber.Length-6))' 或者通过插入 ToListSync()。看到了吗 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,它会产生相同的错误。我理解错误信息。但是,让SQLServer在T-SQL中使用CAST或CONVERT将字符串解析为int很简单,我希望有一种简单的方法来编写查询,以便将其转换为服务器端操作,对吗?

    更新 在克劳迪奥出色的回答之后,我想我应该为下一个来的人补充一些信息。我之所以认为解析是上述代码的问题,是因为以下代码运行时没有错误,并产生正确的结果:

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

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

    就是这样 清晰地 Substring

    0 回复  |  直到 4 年前
        1
  •  2
  •   Claudio Valerio    4 年前

    免责声明:虽然可行,但我强烈建议您不要在查询中使用类型转换,因为这会导致严重的查询性能下降。

    事实是 Convert.ToInt(x) c.ClaimsNumber.Substring(c.ClaimNumber.Length - 6) ,EF核心转换器无法在t-SQL中进行翻译。

    RIGHT 函数存在于Sql Server中,而且,您将无法将其与当前版本的EF Core一起使用(我正在编写的最后一个版本是3.1.2)。 获得所需内容的唯一解决方案是创建一个sqlserver用户函数,将其与EF Core映射并在查询中使用它。

    > 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核心上下文

    在上下文类[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]
    

    另外,当ClaimNumber的最后6个字符首次包含非数字字符时,这将不再有效。如果索赔编号是由人输入的,迟早会发生这种情况。

    您应该为数据库和应用程序编码和设计健壮性,即使您非常确定这6个字符始终代表一个数字。他们不可能永远这么做:)

    推荐文章