LINQ FirstOrDefault带谓词,如果未找到则使用FirstOrDefault。

3

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

我目前在使用:

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

ReSharper 给我一个警告 (Possible multiple enumeration of IEnumerable)。这个警告告诉我我的 SQL 语句可能会被执行两次。一次是为了查找“C”类别,另一次是为了获取第一条记录。如果我先使用 categories.ToList() 将类别转换为列表,则警告将消失。但是如果 categories 包含大量记录,则可能会变慢。

有没有更优雅的方法来处理这个问题?还是我应该忽略这个警告?


如果你想在代码中对任意的 IEnumerable 进行此操作,我建议使用自定义扩展方法;但是考虑到这些项目来自 SQL 服务器,如果你想避免始终迭代所有记录,你需要在数据库服务器上进行操作。我认为不太可能有一组可以自动转换的 LINQ 方法,所以我的建议是使用存储过程。 - AakashM
3个回答

1
如果您的类别表中有一个序列列,您可以这样做:
var category = categories.Where(c => c.SomeSequentialId == 1 || c.Category == "C")
.OrderByDescending(c => c.SomeSequentialId)
.FirstOrDefault();

1
如果你真的担心性能问题,FirstOrDefault 的时间复杂度为 O(n)。只有在第一个查询为 null 时才会执行第二个查询。你可以尝试使用 .Any(predicate)。First() 更适合用于 try { } catch 中,这可能更适合你的情况。
不过,在性能优化成为问题之前,你不必担心它。

1
ReSharper的警告更像是一条消息,提示“考虑一下你正在做什么”,而不是“你做错了”。
您的解决方案并不那么糟糕,但一切都取决于情况。
在生产环境中,类别不存在的情况有多常见?如果很少发生,那么可以保留您的代码。还要考虑执行此代码的频率。它是每天一次还是每秒十次?如果更像前者,那么请将其保留为原样。
否则,微小的优化可能会带来好处。像Seyana这样的解决方案可能有效,或者您可以重写查询以进行union(),并使用Take(1),这样只会向SQL Server发送一个查询;但这并不意味着数据库引擎不会执行两个查询。
分析将为您提供哪种解决方案最快或使用资源最少的答案。

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