【问题标题】:Convert string to int in an Entity Framework linq query and handling the parsing exception在实体框架 linq 查询中将字符串转换为 int 并处理解析异常
【发布时间】:2012-10-01 16:27:24
【问题描述】:

我有这个问题,我有一张桌子供购买

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() 不能与著名的 ToString() 一样用于 linq 查询

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

这是我的扩展

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

【问题讨论】:

  • Number 字段在您的表中声明为 string 的任何原因?
  • 我们能看到你创建的扩展吗?
  • 如果抛出异常,你如何处理?继续求和还是停止?
  • Parse 仅在值不是数字时才抛出异常...为什么您有一个名为 Number 的字段实际上是一个甚至可能不代表数字的字符串!
  • 很抱歉,但请大家不要问为什么,请回答如何,因为我给出了最简单的情况,我的应用程序太复杂了,除此之外我别无选择数字(字符串)

标签: c# linq entity-framework


【解决方案1】:

第一种方式:

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 上下文并验证了它的工作原理。

【讨论】:

  • 你应该总是添加DefaultIfEmpty 我们不想看到另一个例外
  • int.TryParse 不会抛出异常。如果int.TryParse 返回false,则三元为您提供默认值,这意味着转换失败。
  • 您还可以对这些查询使用变体来确定哪些查询未转换。 int temp3; var noConvert = Purchases.Select(x => x.Number).ToList().Where(n => int.TryParse(n, out temp3) == false);
  • 应该注意的是,通过枚举数据集,您将所有用于查询的数据从数据库中拉到内存中。如果您正在执行需要转换为 int 的轻量级查询,那么这将是低效的,并且会在内存中进行进一步的操作,而不是在数据库中。
  • 正如@Carson 所指出的,这个解决方案是非常糟糕的建议,这是新接触 EF 的开发人员在其应用程序中遇到性能不佳的根本原因。 EF.Core 对此提供支持,在 EF6 中只需坚持使用字符串,将您的数字转换为字符串以便在可能的情况下进行比较,将.ToList() 或其他IEnuerable 解决方案留作最后的手段。
【解决方案2】:

我不明白你为什么不想要这个异常,因为如果你的强制转换失败,那么这意味着你的应用程序出了点问题(或者至少,我明白了)。我也不明白为什么要将应该是数字的内容保存为数据库中的字符串。通常,您会将其保留为数字,这样您以后就不必处理此类问题,并且如果有人尝试插入错误的值,您将无法插入。

但是 - 如果你确实想让这条线正常工作,你应该使用int.TryParse,如果值转换成功,它将返回 true,并将值放入查询之外的 'out' 成员中。像这样:

int tmp;
Purchases.Select(X=>int.TryParse(X.Number, out tmp) ? tmp : 0).Max()

而不是“0”,而是使用一些不会与您的逻辑混淆的默认值。

【讨论】:

  • 您不能在 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.
  • 你可以让它工作,但是添加 Purchases.ToList(),但是你会加载整个数据,这可能是很多数据,而且它不会很好地扩展。您还可以在数据库中添加视图,它在 SQL 中进行转换(如果您坚持将原始数据保留为字符串),然后仅返回具有有效整数的行。
猜你喜欢
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多