我正在寻找一种干净的方式来编写这个Linq查询。
基本上我有id的对象集合,然后使用nhibernate和Linq,我需要检查nhibernate实体是否有一个子类集合,其中对象集合中的所有id都存在于nhibernate子类中采集。
如果只有一个项目可行:
var objectImCheckingAgainst = ... //irrelevant
where Obj.SubObj.Any(a => a.id == objectImCheckingAgainst.Id)
现在我想以某种方式传递一个objectImCheckingAgainst列表,并且只有当Obj.SubObj集合包含基于Id的objectImCheckingAgainst列表中的所有项目时才返回true。
答案 0 :(得分:1)
我喜欢使用GroupJoin
。
return objectImCheckingAgainst.GroupJoin(Obj.SubObj,
a => a.Id,
b => b.id,
(a, b) => b.Any())
.All(c => c);
我认为这个查询应该或多或少是不言自明的,但实际上,这会使用各自的id作为键来连接两个集合,然后对这些结果进行分组。然后,对于每个分组,它确定是否存在任何匹配。最后,它确保所有分组都有匹配。
我有时使用的有用替代方法是.Count() == 1
而不是.Any()
。显然,不同之处在于您是否要支持具有相同id匹配的多个元素。根据你的描述,它听起来无论是无关紧要还是由其他方式强制执行。但无论如何,这都是一种轻松的交换。
GroupJoin
中我知道的一个重要概念是相关的,但可能是也可能不是显而易见的,是第一个可枚举的(也就是说,扩展方法的第一个参数,或objectImCheckingAgainst
在这个例子中)将包含在结果中的所有元素,但第二个可能会或可能不会。它与Join
不同,排序无关紧要。如果您习惯使用SQL,则这些是LEFT OUTER JOIN
的基本开头。
另一种可以完成此任务的方法,更简单但不那么有效,就是简单地嵌套查询:
return objectImCheckingAgainst.All(c => Obj.SubObj.Any(x => x.id == c.Id));
我这样说是因为它与您提供的示例非常相似。
我对NHibernate没有任何经验,但我知道很多ORM(我相信包含EF)会将此映射到SQL,因此效率可能会或可能不会成为问题。但总的来说,我喜欢尽可能接近标准写LINQ,所以它在内存中与数据库一样好,所以我会选择我提到的第一个。
答案 1 :(得分:1)
我不熟悉LINQ-to-NHibernate但是当使用LINQ对抗任何SQL后备时,始终注意生成的SQL总是很重要。我认为这是条款......
where Obj.SubObj.All(a => idList.Contains(a.id))
...将生成最好的SQL(具有IN
语句)。
idList
是从Id
个对象列表中提取的objectImCheckingAgainst
列表。