【问题标题】:Filter items from database based on a List<>根据 List<> 从数据库中过滤项目
【发布时间】:2015-10-05 12:58:19
【问题描述】:

我有一个方法可以接受两个List&lt;int&gt;,为此我需要根据List&lt;&gt;s 从数据库中获取数据。

因此,例如,我收到了 List&lt;PersonId&gt; 和 List&lt;NationalityId&gt;,我需要获取记录与 PersonIds 和 NationalistIds 匹配的结果集。

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

请注意,我认为 Lists 可能为空。

有没有有效的方法? 我打算试试:

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

但这会产生相当低效的 SQL,而且当我添加更多搜索参数时,linq 可能会变得非常混乱。

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

join 方法可能很容易阅读,但我面临的问题是如果输入列表为空,那么它不应该过滤。也就是说,如果国籍为空,则不要过滤掉:

    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();

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

【问题讨论】:

  • "但这会产生相当低效的 SQL" - 你怎么知道的?过滤最好在数据库中完成.....
  • @MitchWheat,虽然你说的是真的,但在这种特殊情况下,如果列表包含超过 2000 个组合的项目,则生成的查询将根本无法执行 - 中的所有值每个列表都被转换为一个参数,并且 sql 查询对参数数量有限制。
  • sql 查询中的最大参数数为 2100。在单个参数中传入 CSV 值列表(并使用表值拆分函数将这些值转换为行),或使用表值参数将比处理所有这些输入参数容易得多。
  • 加入列表 似乎是有效的,假设连接会生成内部连接?如果是这样,我该如何做到这一点,如果列表为空或 null,则必须返回所有值?

标签: c# linq


【解决方案1】:

如果您将IQueryable 与IEnumerable(在本例中为entities.Persons 和persons)连接起来,您的过滤将不会在您的查询中进行。而是枚举您的 IQueryable,从数据库中检索您的所有记录,同时使用 IEnumerable 连接方法在内存中执行连接。

要对查询中的列表执行过滤,有两个主要选项:

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

  2. 对您的列表使用包含运算符。这仅适用于小列表,因为每个额外的 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,并且仅在集合中有任何 id 时才应用。

【讨论】:

  • 因此,在上面的示例中,第一行不会查询数据库。然后,我可以为需要检查的两个列表设置两个“if”语句。即添加两个 where 子句,Linq 会以某种方式“合并”它们?然后查询只在最后的.ToList()中执行?
  • @Craig 是的,这是正确的。使用 from / join 语法的 LINQ 查询只是编译器将其转换为对 Queryable 或 Enumerable 静态方法(取决于类型)的调用的语法糖。 LINQ 语句的执行总是延迟到枚举(例如使用ToList)。在Enumerable 的情况下,每个调用都会建立一个管道以流式处理项目。在Queryable 的情况下,每个调用都建立在一个表达式树上,该表达式树被转换为数据存储操作(例如 SQL 查询)。
【解决方案2】:

如果您想获取人员的所有记录,例如如果列表为空,然后按 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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 2020-06-30
    • 2020-09-04
    • 2019-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多