获取第一个单一匹配元素或者如果没有匹配则获取第一个元素?

3

LINQ 中,是否有可能编写一个好的一行代码,以获取集合中的第一个匹配元素或如果没有匹配,则获取第一个元素

例如,您有一组鹦鹉,您想要黄色的鹦鹉,但如果没有黄色的鹦鹉,则任何一个都可以,就像这样:

Parrots.MatchedOrFirst(x => x.Yellow == true)

我正在尝试避免向SQL Server发送双重请求,在这种特殊情况下我们使用的ORM是Dapper


我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
太棒了!感谢您指出有关问题标签和编辑标题的讨论。 - user1249170
3个回答

4

关于:

var matchedOrFirst = Parrots.FirstOrDefault(x => x.Yellow == true) 
    ?? Parrots.FirstOrDefault();

编辑

对于结构体,应该可以这样操作:

var matchedOrFirst = Parrots.Any(x => x.Yellow == true) 
    ? Parrots.First(x => x.Yellow == true)
    : Parrots.FirstOrDefault();

1
应该只是 ?? Parrots.FirstOrDefault() - Ilian
谢谢,这很有道理。我的当前实现是Parrots.FirstOrDefault(x => x.Yellow == true) ?? Parrots.First(),但是(我想我应该提到)我想避免多次与SQL Server的往返。 - user1249170
1
如果您需要将此转换为 SQL Server LINQ,请标记您正在使用的 ORM,如 LINQ-to-SQL、Entity Framework、NHibernate 等。因为答案会因一个到另一个的不同而有所不同。@user1249170 - Jon Adams

2

编辑:这是一个Linq to SQL的解决方案

首先打造一个便捷的扩展

public static T MatchedOrFirstOrDefault<T>(this IQueryable<T> collection, System.Linq.Expressions.Expression<Func<T, Boolean>> predicate)
{
  return (from item in collection.Where(predicate) select item)
                    .Concat((from item in collection select item).Take(1))
                    .ToList() // Convert to query result
                    .FirstOrDefault();
}

使用代码

var matchedOrFirst = Parrots.MatchedOrFirstOrDefault(x => x.Yellow);

0

如果您想避免第二个 SQL 调用,并且需要分支逻辑,那么 Dapper 不太可能知道如何将您提出的 LINQ 查询转换为适当的 SQL IIF、CASE 或其他 SQL 特定函数。

我建议您编写一个简单的存储过程来完成这项工作,并从 Dapper 中调用它。

不过,根据其使用情况,如果此页面已经有一两个查询,并且与服务器相对靠近(延迟方面),第二个简单的 SELECT 对整个应用程序的影响不会太大。除非它在循环中或者您的示例与第一个 SELECT 的成本相比微不足道。


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