【问题标题】:entity framework: conditional filter实体框架:条件过滤器
【发布时间】:2012-07-13 07:11:42
【问题描述】:

假设我有客户表,我想通过以下方式对其进行过滤:

  • 国家:所有、美国、英国、加拿大
  • 收入:全部、低、高、中
  • 年龄:所有,青少年,成人,老年人

如果我必须为这个过滤器构建一个 SQL 字符串,它会是这样的:

if (Country != "All") sql += "country = " + Country
if (Income != "All") sql += "and income = " + Income
if (Age != "All") sql += "and age = " + Age;

因此,基本上,用户可以按一些字段进行过滤,但不必过滤所有字段。

你如何使用实体框架做到这一点?

谢谢!

【问题讨论】:

  • 同意。完毕。谢谢回复。 PS:我也是明斯克人。

标签: entity-framework c#-4.0


【解决方案1】:

LINQ to Entity 查询返回 IQueryable,因此您可以这样构建查询:

IQueryable<Person> query = context.People;

if (Country != "All")
{
    query = query.Where(p => p.Country == Country);
}

if (Income != "All")
{
    query = query.Where(p => p.Income == Income);
}

if (Age != "All")
{
    query = query.Where(p => p.Age == Age);
}

List<Person> fetchedPeople = query.ToList();

这种情况几乎太简单了,但是这在需要动态添加过滤的更复杂的情况下非常有用。

【讨论】:

  • 我用这种方法很久了,我只是分析了结果查询,它似乎以这种方式添加过滤,query = query.Where,不影响SQL,过滤返回行后最终在内存中完成。在本例中,由于初始查询只是 context.People,因此数据库将在 ToList() 上返回整个 People 表,然后 EF 在内存中对其进行过滤。
  • 我已经很久没有使用EF了,但这听起来有点奇怪,而且不太可能。 C# 没有办法“记住”query 变量的旧值,在此示例中,它被包含过滤器的新值覆盖。如果您改用新的变量名,有什么区别吗?比如filteredQuery?或者(为了比较)您是否尝试过使用从一开始(而不是有条件地)应用的所有过滤器和分析来创建查询?我猜这三种情况的结果都是一样的。
  • 我分析了在定义行中应用的过滤器和稍后应用的过滤器。生成的 SQL 非常明显,它只有在定义行中的 WHERE 子句。我同意它不能“记住”来自定义行的原始查询,但它不会将新过滤器扩展到原始查询,它只是等待取回行并在之后过滤。这就是人们使用 PredicateBuilder 或 LINQKit 之类的东西的原因。
【解决方案2】:

您可以通过这种方式包含条件参数:

return Customers.Where(
                customer =>
                customer.Name == Name &&
                (Age == "All" || customer.Age == Age) &&
                (Income == "All" || customer.Income == Income) &&
                (Country == "All" || customer.Country == Country)
                ).ToList();

如果某些条件为真(例如国家等于All),则所有参数条件都为真,并且该参数不过滤结果。

【讨论】:

  • 这种方法在2019有什么缺点吗?
  • @ninbit 那是很久以前的事了。我会使用条件组合而不是所有参数的单一条件。
  • 但是如果我们在合成后select 就不行了。你有什么主意吗?错误类似于it doesn't have the method 'select'
【解决方案3】:

您可以使用扩展方法来帮助代码的可读性和可维护性。

  • LinqExtensions.cs
public static class LinqExtensions
{
    public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate)
    {
        return condition ? source.Where(predicate) : source;
    }
}
  • 重构代码
List<Person> peoples = context.People
    .WhereIf(Country != "All", p => p.Country == Country)
    .WhereIf(Income != "All", p => p.Income == Income)
    .WhereIf(Age != "All", p => p.Age == Age)
    .ToList();

【讨论】:

    猜你喜欢
    • 2017-11-08
    • 2015-12-29
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多