首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在EF Core 3查询中解析int?

如何在EF Core 3查询中解析int?
EN

Stack Overflow用户
提问于 2020-03-02 22:31:58
回答 2查看 3K关注 0票数 4

升级到EF Core 3后,我将在以下代码中得到以下错误:

Convert.ToInt32(c.ClaimNumber.Substring(c.ClaimNumber.Length System.InvalidOperationException:‘LINQ表达式'DbSet .Max(c => .Max-6)’)无法翻译。要么用可以翻译的表单重写查询,要么通过插入对AsEnumerable()、AsAsyncEnumerable()、ToList()或ToListAsync()的调用,显式地切换到客户端计算。更多信息请参见https://go.microsoft.com/fwlink/?linkid=2101038

代码语言:javascript
复制
var maxId = Db.Claims
    .Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
    .Max(x => Convert.ToInt32(x));

我也尝试过使用int.Parse而不是Convert.ToInt32,并且它会产生同样的错误。我理解错误信息。但是,要让Server在that中使用强制转换或转换将字符串解析为int非常简单,我希望有一种简单的方法来编写查询,以便将其转换为服务器端的操作,对吗?

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

代码语言:javascript
复制
var maxId = Db.Claims
    .Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
    .AsEnumerable()
    .Max(x => int.Parse(x));

但是,我深入研究发现,这是SQL查询EF从该代码中执行的:

代码语言:javascript
复制
SELECT [c].[ClaimNumber], CAST(LEN([c].[ClaimNumber]) AS int) - 6
FROM [Claims] AS [c]
WHERE [c].[ClaimNumber] IS NOT NULL

这显然不是我想做的事情,因此克劳迪奥是对的,对Substring的调用实际上就是问题所在。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-03-03 00:13:34

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

事实上,Convert.ToInt(x)部分不是这里的问题。是c.ClaimsNumber.Substring(c.ClaimNumber.Length - 6),EF翻译器无法在T中进行翻译.

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

1)通过迁移创建函数

代码语言:javascript
复制
> dotnet ef migrations add CreateRightFunction

在新创建的迁移文件中,放入以下代码:

代码语言:javascript
复制
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
");
    }
}

然后运行db更新:

代码语言:javascript
复制
dotnet ef database update

2)映射函数到EF核心上下文

在上下文中classDbFunction("fn_Right")

代码语言:javascript
复制
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)在查询中使用函数

代码语言:javascript
复制
var maxId = Db.Claims.Select(c => MyContext.Right(c.ClaimNumber, 6)).Max(x => Convert.ToInt32(x));

生成的查询:

代码语言:javascript
复制
SELECT MAX(CONVERT(int, [dbo].[fn_Right]([c].[ClaimNumber], 6)))
FROM [Claims] AS [c]

同样,这与最佳实践相去甚远,我认为您应该考虑在表中添加一个int列来存储这个“数字”,不管它在您的域中代表什么。

另外,当ClaimNumber的最后6个字符包含一个非数字字符时,这将不再起作用。如果ClaimNumber是由人类输入的,迟早会发生这种情况。

您应该为健壮性编写和设计数据库和应用程序,即使您非常确信这6个字符总是代表一个数字。他们不能永远这样做:)

票数 5
EN

Stack Overflow用户

发布于 2021-10-06 15:11:32

请按以下方式更改您的代码。它适用于我的Dotnet核心3.1版本

代码语言:javascript
复制
var maxId = Db.Claims.Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
    .Max(x => (Convert.ToInt32((x == null)? "0" : x.ToString())));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60497605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档