在Entity Framework的linq查询中将字符串转换为整数并处理解析异常

14

我有一个问题,我有一个购买表格

Purchases(Date DateTime, Number string)

我想要创建一个新的记录,因此我需要Max(Number)。问题在于Number是一个字符串,我尝试过

Purchases.Select(X=>int.Parse(X.Number)).Max()

但它可能会抛出异常,我已经创建了一个自定义的 ToInt() 扩展,这样当我使用它时

Purchases.Select(X=>X.Number.ToInt()).Max()

它会抛出一个异常,说我的ToInt()不能与linq查询一起使用,和著名的ToString()一样。

所以我问题是:有没有一种方法可以在linq查询中将字符串转换为int并同时处理异常,或者将自定义函数集成到linq查询中!!

这是我的扩展

    public static int ToInt(this string s)
    {
        try
        {
            return int.Parse(s);
        }
        catch
        {
        }
        return 0;
    }

5
你的表格中为什么将Number字段声明为string类型? - Darin Dimitrov
如果出现异常,您会如何处理?继续求和还是停止? - cuongle
当发生异常时,它会将我的扩展名设置为零。@CuongLe - S3ddi9
2
“Parse”只有在值不是数字时才会抛出异常……为什么你有一个名为“Number”的字段,实际上是一个字符串,甚至可能不代表一个数字! - verdesmarald
1
很抱歉,但请大家不要问为什么,而是回答如何,因为我已经给出了最简单的情况,我的应用程序太复杂了,我别无选择,只能使用 **Number(string)**。 - S3ddi9
显示剩余4条评论
2个回答

21

第一种方式:

var numbers = Purchases.Select(x => x.Number).ToList();

int temp;
int max = numbers.Select(n => int.TryParse(n, out temp) ? temp : 0).Max();

Console.WriteLine("Max: {0}", max);

第二种方法:

int temp2;
int max2 = Purchases.Select(x => x.Number).ToList().Select(n => int.TryParse(n, out temp2) ? temp2 : 0).Max();

Console.WriteLine("Max 2: {0}", max2);
关键在于这两种方式中的 `.ToList()`,它会从数据库获取所有的 `string` 数据,因此当你对结果调用 `int.TryParse` 时,数据库查询已经完成,所以它使用的是纯 CLR 代码,而不是尝试将 `int.TryParse` 转换成 SQL 查询。我在我的一个沙盒项目中创建了一个 EF 上下文并验证了这一点。

1
你应该总是添加 DefaultIfEmpty,我们不想看到另一个异常。 - S3ddi9
int.TryParse 不会抛出异常。如果 int.TryParse 返回 false,表示转换失败,那么三元运算符将为您提供默认值。 - Gromer
您还可以使用这些查询的变体来确定哪些不会转换。int temp3; var noConvert = Purchases.Select(x => x.Number).ToList().Where(n => int.TryParse(n, out temp3) == false); - Gromer
2
需要注意的是,通过枚举数据集,您正在将查询的所有数据从数据库中拉入内存。如果您正在执行一个较轻量级的查询,并且需要转换为int类型,那么这将是低效的,并且会在内存中执行进一步的操作,而不是在数据库中执行。 - Carson
1
如@Carson所指出的,这个解决方案是极其糟糕的建议,是导致EF新开发者应用程序性能差的根本原因。EF.Core已经支持此功能,在EF6中只需使用字符串,将数字转换为字符串进行比较,将.ToList()或其他IEnuerable解决方案留作最后的手段。 - Chris Schaller

2
我不明白为什么您不想要异常,因为如果强制转换失败,则意味着应用程序出现了问题(至少我是这样认为的)。我也不明白为什么要将本应为数字的内容保存为字符串在数据库中。通常,您会将其保存为数字,以便以后不必处理此类问题,并且如果有人尝试插入错误值,则插入操作将失败。
但是-如果您确实想使这行代码工作,您应该使用int.TryParse,它将在成功转换值时返回true,并将值放入“out”成员中,该成员将超出查询范围。像这样:
int tmp;
Purchases.Select(X=>int.TryParse(X.Number, out tmp) ? tmp : 0).Max()

而不是使用“0”,请放置一些默认值,这样不会影响您的逻辑。


7
在_EF_查询中不能使用int.TryParse方法。这会导致以下异常:Unhandled Exception: System.NotSupportedException: LINQ to Entities does not recognize the method 'Boolean TryParse(System.String, Int32 ByRef)' method, and this method cannot be translated into a store expression. - Gromer
3
你可以通过添加"Purchases.ToList()"使它工作,但这样会加载整个数据,可能是大量的数据,并且不会很好地扩展。你还可以在数据库中添加视图,在SQL中执行转换(如果你坚持将原始数据保留为字符串),然后仅返回有效整数行。 - Shahar Gvirtz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接