Linq, is select().SingleorDefault() 一个坏主意

本文关键字:一个 SingleorDefault is select Linq | 更新日期: 2023-09-27 18:21:53

 var queueitem = context.CrawlerQueues.
                 Select(cq => new{cq.Guid,cq.Result}).
                 SingleOrDefault(cq => cq.Guid == guid);

这是一个坏主意,它会首先选择所有数据库行,然后找到一个,还是很聪明并查看其使用的上下文并仅获取一行。

这样做的原因是我只想返回 Guid 和结果列。

return Newtonsoft.Json.JsonConvert.SerializeObject(queueitem, Formatting.Indented);

如何在不监视网络流或对数据库发出的请求的情况下找到答案?

Linq, is select().SingleorDefault() 一个坏主意

"它会先选择所有数据库行,然后找到一个">

从技术上讲,不,.选择,然后选择 。SingleOrDefault 不会这样做。 Select(( 为查询设置参数,但它实际上并没有获取任何数据。 LINQ 的延迟执行不会提取任何行,直到某些内容实际必须生成数据结果。您可以将多个查询组合在一起 (.选择(...(。select(..( 等(,在您执行返回数据的操作(例如 First(( 或 .ToList((。

但是,使用 Single(( 可能会导致扫描整个数据集以证明一个匹配的行是唯一匹配的行。

想一想:查询如何知道一行是数据集中唯一匹配的行?它将不得不尝试找到下一行。 如果数据集中只有一行匹配,则 Single(( 可能必须遍历所有这些数百万行,以证明当前匹配是唯一匹配的。

如果您的数据集是 SQL,并且您的数据以允许查询优化的方式编制索引,那么 Single(( 可能不会那么糟糕。 但是,如果 SQL 数据的索引方式未对此查询有帮助,则 Single(( 可能会为 SQL 服务器创建大量工作。

如果您的程序逻辑确实需要知道返回的行是整个数据集中的唯一行,则 Single(( 是合适的。但是,还有其他方法可以保证唯一性。如果可以在数据上设置与 LINQ 条件匹配的主键,则一开始只能存在一个匹配的行/添加到数据库中,因此您实际上不需要 Single((。(具有讽刺意味的是,在这种情况下,Single(( 的性能也会非常快,因为主键索引可用于优化查询(

如果只想要与条件匹配的第一行,请使用 First(( 而不是 Single((。 First(( 只需要扫描数据行,直到找到第一个匹配项。 它不必继续扫描行来证明第一个匹配项是唯一匹配项,例如 Single((。

SingleOrDefault - 返回序列的唯一元素,如果序列为空,则返回默认值;如果序列中有多个元素,则此方法将引发异常

FirstOrDefault - 返回序列的第一个元素,

如果序列不包含任何元素,则返回默认值。

从语义上讲,您希望FirstorDefault因为您的问题提到了返回的多行。

我很确定这不会在过滤之前返回整个数据库,因为查询的执行直到"评估"语句执行之后才会发生,这是此查询中的 SingleOrDefault((。

如果你有

context.CrawlerQueues.ToList().Select(cq => new{cq.Guid,cq.Result}).SingleOrDefault(cq => cq.Guid == guid) ;

然后,这将在过滤之前评估ToList(),但查询很好。

如果您不确定评估路径或从 LINQ 语句生成的 SQL,LINQPad 是一个非常好的工具,它使使用 Linq、Linq2Sql、EF 变得非常容易。

实际执行的查询实际上取决于 Linq 提供程序,但是是的,Linq 提供程序直到最后一刻才会计算,因此它将在执行查询之前知道上下文 (SingleOrDefault(。一个好的不会不必要地获取任何东西。

一个好的 Linq 实现实际上会获取 2 行,因为 SingleOrDefault 会处理 3 种情况;

  • 不返回任何行 -> 返回默认值
  • 返回一行 -> 返回该行
  • 返回多行 -> 引发异常(序列包含多个元素(
相关文章: