干净的方式来编写此查询

时间:2015-03-18 07:18:36

标签: linq

我正在寻找一种干净的方式来编写这个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。

2 个答案:

答案 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列表。