首页 > 解决方案 > 将整数谓词与 LINQ 进行比较

问题描述

我有这个简单的查询,我需要在 EF Core 的 api 端识别特定 TicketBook 对象的开始和结束编号内的所有票证。

var ticketBook = await Context.TicketBooks.FirstOrDefaultAsync(x=>x.Id == query.TicketBookId);
if (ticketBook != null)
{
      dbTickets = dbTickets.Where(x => ConvertTicketNumberToInt(x, ticketBook));
}

private bool ConvertTicketNumberToInt(Ticket t, TicketBook tb)
{
        try
        {
            var numberOnly = new string(t.Number.Where(t => char.IsDigit(t)).ToArray());
            var tNumber = Convert.ToInt64(numberOnly);
            return tNumber >= tb.StartIntNumber && tNumber <= tb.EndIntNumber;
        }
        catch(OverflowException)
        {
            return false;
        }
}

问题是 Ticket 类中的“数字”属性是 nvarchar(字符串),但我需要将它转换为整数,仅用于这个特定的查询,为此我编写了一个小方法来为我做这件事。但是正如您所看到的那样,它非常耗时且根本没有效率,所以我的 api 调用只是超时了。

我试图弄清楚如何在 LINQ 中做到这一点,而无需编写像这样的额外方法。诀窍是“数字”属性有时可以在其中包含一些字母,这会在将其转换为整数时引发异常,因此我需要在比较之前删除那些非数字字符,这就是为什么我必须为它编写这个专用方法的原因。

标签: c#linqasp.net-coreentity-framework-corelong-integer

解决方案


如前所述,您面临存储nvarchar而不是长时间存储的一些性能问题。

无论如何,您在代码中所做的事情并没有那么糟糕——您有相当简单的方法可以让您的 LINQ 代码保持干净整洁。但是由于您想要一个 LINQ 查询,请尝试以下操作(它可以做得更短,但我选择这种方式是为了便于阅读):

var ticketBook = await Context.TicketBooks.FirstOrDefaultAsync(x=>x.Id == query.TicketBookId);
if (ticketBook != null)
{
    dbTickets = dbTickets
        .Select(t => new { Ticket = t, Number = new string(t.Number.Where(n => char.IsDigit(n)).ToArray()) })
        .Select(t => 
        {
            long ticketNumber = long.MinValue;
            long.TryParse(t.Number), out ticketNumber);
            return new { Ticket = t, Number = ticketNumber };
        })
        .Where(t => t.Ticket >= ticketBook.StartIntNumber && t.Ticket <= ticketBook.EndIntNumber)
        .Select(t => t.Ticket);
}

它能做什么:

  • 在第一次传递中,您的所有字母都被剥离并转换为仅包含数字的字符串,然后与此字符串一起返回具有varchars完整类的匿名类型Ticket
  • 字符串被解析为很长 - 我滥用long.MinValue表示转换失败(因为你正在使用char.IsDigit(c)我看到你不希望结果中有任何负值。你最好使用ulong两倍的正范围并滥用 0 值) 再次返回一个匿名类型
  • 这些匿名结构会根据您提供的条件进行过滤
  • 最后,只返回原始Ticket结构

如果您担心初始结果的通过次数 - 我已经运行了几次性能测试,以确定Select内部是否有许多带有短操作的 s 是否比使用复杂操作的一次通过要慢,我没有观察到任何显着差异。


推荐阅读