2015-10-05 91 views
1

我有一种方法,接受两个List<int>我需要从数据库中获取基于List<> s的数据。从数据库中筛选项目基于List <>

所以,我收到例如List<PersonId>List<NationalityId>,我需要得到一个结果集,其中记录匹配PersonIdsNationalistId秒。

public List<PersonDTO> SearchPeople(List<int> persons, Lisy<int> nationalities) 
{ 
    var results = (from c in myDbContect.People where .... select c).ToList(); 
} 

请注意,我认为列表可能为空。

有没有一种有效的方法? 我要去尝试:

where ((persons != null && persons.Count > 0) && persons persons.Contains(x=>x.PersonId)) 

但是,这会产生相当低效的SQL,并为我添加更多的搜索参数,LINQ的可能会非常混乱。

有没有一种有效的方法来实现这一目标?

连接方法可能很容易阅读,但我面临的问题是,如果输入列表为空,那么它不应该过滤。也就是说,如果民族是空的,没有任何过滤出来:

var results = (from c in entities.Persons 
        join p in persons on c.PersonId equals b 
        join n in nationalities on c.NationalityId equals n 

等于n 选择C).ToList();

如果任何列表为空,则不会返回结果。哪个不好。

+3

“但这会产生效率相当低的SQL” - 你怎么知道的?过滤最好在数据库中完成..... –

+2

听起来像你想加入... http://stackoverflow.com/questions/2723985/linq-join-2-listts – felickz

+0

@MitchWheat,而你在说什么是真的,在这种特殊情况下,如果列表包含超过大约2000个项目的组合,那么所得到的查询将根本无法执行 - 列表中的所有值均被转换为每个参数,并且sql查询对数量有限制的参数。 –

回答

0

如果你想获得的所有记录,例如人,如果该列表是空的,然后通过nationalityId列表进行过滤,如果它不是空的,你可以做这样的事情:

List<int> personsIds = ...; 
List<int> nationalitiesIds = ...; 

var results = (from c in entities.Persons 
        join p in persons on c.PersonId equals b 
        join n in nationalities on c.NationalityId equals n 
        where ((personsIds == null || personsIds.Contains(p.Id)) 
         && (nationalitiesIds == null || nationalitiesIds.Contains(n.Id)) 
select c).ToList(); 
1

如果你加入的IQueryableIEnumerable(在这种情况下,entities.Personspersons),您的筛选不会发生在您的查询。而是枚举您的IQueryable,从数据库中检索所有记录,而使用IEnumerable联接方法在内存中执行联接。

要针对您的查询中的列表进行过滤使用,主要有两种选择:

  1. 加入双面使用的IQueryable。如果您的id列表来自另一个查询的执行,这可能是可能的,在这种情况下,您可以在联接中使用基础查询,而不是生成的一组id。

  2. 对列表使用contains操作符。这只适用于小列表,因为每个附加的id都需要自己的查询参数。如果你有很多ID,你可以通过批量扩展这个方法。

如果您想在列表为空时跳过筛选,那么您可以考虑使用扩展方法调用而不是LINQ语法。这使您可以使用if声明:

IQueryable<Person> persons = entities.persons; 
List<int> personIds = new List<int>(); 
if(personIds.Count > 0) 
{ 
    persons = persons.Where(p => personIds.Contains(p.PersonId)); 
} 
var results = persons.ToList(); 

注意,Where谓词使用选项#2以上,如果有集合中的任何IDS仅适用。

+0

因此,在上例中,第一行不会查询数据库。然后,我可以为这两个列表添加两个“if”语句,我需要检查它们。即添加两个where子句,Linq会以某种方式“合并”它们?然后查询只在最后的.ToList()中执行? – Craig

+0

@克雷格是的,这是正确的。使用'from' /'join'语法的LINQ查询只是语法糖,编译器将其翻译为对“Queryable”或“Enumerable”静态方法(取决于类型)的调用。 LINQ语句的执行总是推迟到枚举(例如使用“ToList”)。在Enumerable的情况下,每个调用都会建立一个流水线以流式处理项目。在“Queryable”的情况下,每个调用都会建立到一个表达式树上,并转换为数据存储操作(例如SQL查询)。 –