在LINQ查询’where’语句中实现条件’if’语句

我试图找出一种在我的数据模型中查询对象的方法,并且只包含那些非空的参数。 如下所示:

public List GetWidgets(string cond1, string cond2, string cond3) { MyDataContext db = new MyDataContext(); List widgets = (from w in db.Widgets where ... if cond1 != null w.condition1 == cond1 ... ... if cond2 != null w.condition2 == cond2 ... ... if cond3 != null w.condition3 == cond3 ... select w).ToList(); return widgets; } 

由于小部件表可能变得非常大,我想避免这样做:

 public List GetWidgets(string cond1, string cond2, string cond3) { MyDataContext db = new MyDataContext(); List widgets = db.Widgets.ToList(); if(cond1 != null) widgets = widgets.Where(w => w.condition1 == cond1).ToList(); if(cond2 != null) widgets = widgets.Where(w => w.condition2 == cond2).ToList(); if(cond3 != null) widgets = widgets.Where(w => w.condition3 == cond3).ToList(); return widgets; } 

我看了几个例子,但没有看到任何与我需要做的事情相符的事情。

您要避免的是实际执行查询,直到您准备好:

 public List GetWidgets(string cond1, string cond2, string cond3) { MyDataContext db = new MyDataContext(); var widgets = db.Widgets; if(cond1 != null) widgets = widgets.Where(w => w.condition1 == cond1); if(cond2 != null) widgets = widgets.Where(w => w.condition2 == cond2); if(cond3 != null) widgets = widgets.Where(w => w.condition3 == cond3); return widgets.ToList(); } 

请注意如何删除ToList调用。 在您开始迭代之前,不会执行查询。 调用ToList将强制执行此操作,以便将结果放入List<>并返回。 我甚至建议将方法的返回值更改为IEnumerable并最后跳过ToList调用:

 public IEnumerable GetWidgets(string cond1, string cond2, string cond3) { MyDataContext db = new MyDataContext(); var widgets = db.Widgets; if(cond1 != null) widgets = widgets.Where(w => w.condition1 == cond1); // [...] return widgets; } 

这样,调用代码就可以决定何时执行查询(甚至可以在执行此操作之前添加更多条件)。

使用“或门”:在每个小部件条件测试前加上“||” 并检查我们是否正在使用该条件。 如果我们不是,那么“或”的后半部分不会被评估。 这就是为什么它是一个门 – 如果第一部分评估为真,我们就不会再进一步​​了。

如果我正在写它,我会像下面这样做。 我使用var syntatic sugar来保存LINQ查询并将ToList()移到最后。

 public List GetWidgets(string cond1, string cond2, string cond3) { MyDataContext db = new MyDataContext(); var widgets = from w in db.Widgets where (cond1 == null || w.condition1 == cond1) && (cond2 == null || w.condition2 == cond2) && (cond3 == null || w.condition3 == cond3) select w; return widgets.ToList(); } 

编辑:语法

这样的事怎么样?

  IEnumerable condQuery = (from w in db.Widgets); if(cond1 != null ) condQuery = condQuery.Where(w=> w.condition1 == cond1); if(cond2 != null ) condQuery = condQuery.Where(w=> w.condition2 == cond2); 

等等…?

您实际上是 linq查询中要求调度程序。 Where方法采用谓词,因此您可以在创建查询之前构建谓词。

– 编辑 – 起初,我认为这更容易,写了一些甚至没有编译的伪代码。 现在,无论如何,我想我明白了。 这段代码可行; 它将where子句与应用它分开。

  static Predicate combine( Predicate existing, Predicate condition ) { var newpred = new Predicate( w=> existing(w) && condition(w) ); return newpred; } 

并使用这样的“建筑”function:

  static void Main(string[] args) { string cond1 = "hi"; string cond2 = "lo"; string cond3 = null; var pr = new Predicate( (Widget w ) => true ); if (cond1 != null) pr = combine( pr, w => w.condition1 == cond1); if (cond2 != null) pr = combine( pr, w => w.condition2 == cond2); if (cond3 != null) pr = combine( pr, w => w.condition3 == cond3); 

我用一个小帮助器数组测试它:

  var widgets = new Widget[]{ new Widget (){ condition1 = "" }, new Widget (){ condition1 = "hi", condition2 = "lo" } }; var selected = widgets.Where( (w) => pr(w)); foreach (var w in selected) { Console.WriteLine(w); } 

我们可以使用下面非常简单的方法。

 (from e in employee join d in departments on e.departmentId equals d.departmentId Select new { e.name, d.name, getEmployeeContacts(e) } //return active contact if not return first . This is same like if else along with null check private contact getEmployeeContacts(Employee e ) { return e.Contacts.FirstOrDefault(x => x.Active == 1) ?? e.Contacts.FirstOrDefault(); }