2014-02-08 82 views
10

我有一个实体Person,其中包含与其关联的位置列表。我需要查询个人表,并从位置列表(标准)中获取所有至少有一个位置的人。下面的作品,但效率非常低:检查列表是否包含来自EntityFramework中其他列表的项目

var searchIds = new List<int>{1,2,3,4,5}; 
var result = persons.Where(p => p.Locations.Any(l => searchIds.Any(id => l.Id == id))); 

这对小名单(比如5-10 searchIds和5-10位置的人能正常工作的问题是,有些人可能有100个地点和搜索即可。当我试图执行上面的EF时,实际上产生了2000多条SQL语句,并且因为嵌套过于深入而失败了,虽然嵌套本身已经是一个问题,即使它可以工作, d仍然不会发生在2000+ SQL语句中

注意:真正的代码还包括多层次和父子关系,但我确实设法只用id来代替这个相当平坦的结构,而不是的福ll objects

在EF中完成此操作的最佳方法是什么?

+0

获得2000+ sql时,您传递了多少个ID? – ivowiblo

回答

4

尝试切换到连接的,而不是做一个庞大的数据包括:

var searchIds = new List<int>{1,2,3,4,5}; 
var results = (from p in persons 
       join l in Location on p.PersonId equals l.PersonId 
       where searchIds.Contains(l.Id) 
       select p).Distinct().ToList(); 

显然修复这条线,以配合您的类和/或加入财产。

join l in Location on p.PersonId equals l.PersonId 

我期望生成一个更友好的执行计划。

+0

我与你在ORM上,所以这将是一个快速讨论:-)不幸的是,我不能使用连接,因为我没有位置集(使用通用储存库)。尽管我发现'searchIds.Contains(l.Id)'比'searchIds.Any(id => l.Id == id)好很多。低至约70行的SQL,不超过但超过2000+ – Kenneth

+0

@Kenneth如果你能看到Person类中的'Locations'属性,我不明白你为什么不能直接查询这个类。也许我没有正确理解这种情况。无论如何,我祝你好运。 – Timeout

+0

那么,我只能直接访问一个EntitySet(Persons)。其余的应该是通过这个班级间接查询的。据推测,EF处理连接并找出最佳执行路径。据说...无论如何,这些包含似乎是最重要的部分。感谢您的帮助 – Kenneth

29

我会建议:

var searchIds = new List<int>{1,2,3,4,5}; 
var result = persons.Where(p => p.Locations.Any(l => searachIds.Contains(l.Id))); 

Contains将被转换为IN声明。

请记住,id列表进入sql语句。如果你的ID列表很大,那么你最终会得到一个巨大的查询。

相关问题