LINQ FirstOrDefault with predicate,如果没有找到FirstOrDefault

时间:2013-12-10 17:20:45

标签: c# linq resharper

我正在尝试在IEnumerable中搜索特定记录(使用谓词)。如果该记录不存在,我想返回第一条记录。如果这也不存在,我只想要null

我正在使用

var category = categories.FirstOrDefault(
    c => c.Category == "C") ??
    category.FirstOrDefault();

ReSharper给了我一个警告(可能多次枚举IEnumerable)。警告告诉我我的sql语句可能会被执行两次。一旦尝试找到“C”类,再一次获得第一条记录。如果我首先使用categories.ToList()将类别转换为列表,则警告将消失。但如果类别包含大量记录,那可能会很慢。

有更优雅的方法吗?或者我应该忽略警告?

3 个答案:

答案 0 :(得分:1)

如果您真的担心性能,FirstOrDefault是O(n)。 如果第一个查询为null,则只执行第二个查询。 您可以尝试使用.Any(谓词)。 First()适合尝试{}捕捉,这可能对你的情况更好。

但是,在成为问题之前,您并不需要担心性能优化。

答案 1 :(得分:1)

如果您的类别表中有一个连续的列,您可以执行以下操作:

var category = categories.Where(c => c.SomeSequentialId == 1 || c.Category == "C")
.OrderByDescending(c => c.SomeSequentialId)
.FirstOrDefault();

答案 2 :(得分:1)

ReSharper警告更多的信息是“想想你在做什么”,而不是“你做错了”。

你的解决方案并不是那么糟糕,但这完全取决于具体情况。

在制作中,该类别多久不存在一次?这是一种罕见的情况,然后将代码保留原样。 另一件需要考虑的事情是执行此代码的频率。是每天一次,还是每秒十次? 它更像是第一个吗?保持原样。

否则,微优化可能是有益的。像Seyana这样的解决方案可能有用,或者您可以使用Take(1)将查询重写为union(),因此只有一个查询将发送到SQL Server;但这并不意味着数据库引擎都不会执行这两个查询。

分析将为您提供最快或使用最少资源的解决方案。