LINQ 动态添加 Where 条件

3
我有一个GridView,其中每个标题都有下拉框用于过滤。加载时,每个过滤器都装入其列的不同值。在运行时,我添加“ALL”以允许用户从该字段中选择所有内容。我正在尝试动态构建linq语句以忽略如果下拉框设置为“ALL”的字段。这可行吗?我想看看是否可以在一条语句中完成。下面的示例仅显示了2个下拉框,但我的实际情况最多有5个。
如果选择使用if then语句,则最终会导致混乱的代码。
DropDownList drpOwners = this.grdOtherQuotes.HeaderRow.FindControl("drpOwners") as DropDownList;                     
DropDownList drpCompanyName = this.grdOtherQuotes.HeaderRow.FindControl("drpCompanyName") as DropDownList;

var filteredList = (from x in allQuotes
                          where (drpOwners.SelectedValue != ALL) ? x.SalesRepFullName == drpOwners.SelectedValue:true                                    
                                && drpCompanyName.SelectedValue != ALL ? x.CompanyName == drpCompanyName.SelectedValue: true
                          select x);

你尝试过LinqKit吗?http://www.albahari.com/nutshell/linqkit.aspx - Parwej
3个回答

10

个人而言,我觉得将这个内容分开会更简单:

IEnumerable<Quote> filteredList = allQuotes;
// If using EF or LINQ to SQL, use: IQueryable<Quote> filteredList = allQuotes;
if (drpOwners.SelectedValue != ALL) 
   filteredList = filteredList.Where(x => x.SalesRepFullName == drpOwners.SelectedValue);
if (drpCompanyName.SelectedValue != ALL) 
   filteredList = filteredList.Where(x => x.CompanyName == drpCompanyName.SelectedValue);
// More conditions as needed

这个并不长,而且更容易理解。


如果你真的想把它写成“一行代码”,你可以创建一个扩展方法来构建查询。例如,如果使用Entity Framework:

static IQueryable<T> AddCondition(this IQueryable<T> queryable, Func<bool> predicate, Expression<Func<T,bool>> filter)
{
     if (predicate())
         return queryable.Where(filter);
     else
         return queryable;
}

这将使您能够将其编写为:
var filteredList = allQuotes
                     .AddCondition(() => drpOwners.SelectedValue != ALL, x => x.SalesRepFullName == drpOwners.SelectedValue)
                     .AddCondition(() => drpCompanyName.SelectedValue != ALL, x.CompanyName == drpCompanyName.SelectedValue);

当然,您可以更进一步,制作一个版本,将谓词硬编码为针对“ALL”检查组合框,这样可以使谓词更短(只有组合框)。

它基于IQueryable被返回的事实,因此where子句直到实际需要数据时才被执行。+1 - ΩmegaMan
@OmegaMan,原帖并没有明确说明“allQuotes”是IEnumerable<T>还是IQueryable<T> - 然而,这个方法实际上可以在EF中使用,而原始方法可能无法使用(我认为,在这种情况下的条件运算符,“where true”将无法通过EF映射)。 - Reed Copsey
@ReedCopsey - 你的代码会导致查询执行,因为你正在使用 Func<T, bool>。应该使用 Expression<Func<t,bool>>。 - Erik Funkenbusch
@MystereMan 是的,已经修正了 - 我最初是想写LINQ to Objects,然后在最后一刻改变了主意,忘记修改了 - 现在处理好了。 - Reed Copsey

1

你可以创建一个辅助方法来处理所有逻辑。类似这样:

private bool CompareSelectedValue(string value, string dropDownValue)
{
  if(dropDownValue == "ALL")
    return true;
  else
    return value == dropDownValue;
}

那么你的查询可能是:

var filteredList = (from x in allQuotes
                          where (CompareSelectedValue(x.SalesRepFullName, drpOwners.SelectedValue)                                    
                                && CompareSelectedValue(x.CompanyName, drpCompanyName.SelectedValue)
                          select x);

0
创建扩展方法,封装 where 逻辑,使其看起来更加简洁:
var filteredList = allQuotes.WhereDropOwnersAreContained()
                            .WhereCompanyIsContained()
                            ...
                            ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接