在LINQ查询中执行条件'if'语句'where'语句

问题描述:

我试图找出一种方法来查询我的数据模型中的一个对象,并且只包含那些非空的参数。如下图所示:在LINQ查询中执行条件'if'语句'where'语句

public List<Widget> GetWidgets(string cond1, string cond2, string cond3) 
{ 
    MyDataContext db = new MyDataContext(); 
    List<Widget> 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<Widget> GetWidgets(string cond1, string cond2, string cond3) 
{ 
    MyDataContext db = new MyDataContext(); 
    List<Widget> 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<Widget> 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<Widget>以及跳过到底ToList电话:

public IEnumerable<Widget> 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; 
} 

这样调用代码获取来决定何时执行查询(它甚至可以添加更多的条件在此之前)。

+0

是否由JIT编译器在结果查询中删除条件?或者linq'保证'一些优化? – xtofl 2010-09-21 16:51:43

+0

@xtofl:不确定你的意思?你想摆脱哪些条件? – 2010-09-21 17:49:02

+0

如果条件不满足,它们不会添加到表达式树中。 – Michael 2010-09-22 02:02:43

这样的事情呢?

 IEnumerable<Widget> 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); 

etc ...?

+0

不编译。 – Timwi 2010-09-21 13:59:52

你实际上要求调度员 linq查询。 Where方法接受一个谓词,因此您可以在创建查询之前构建谓词。

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

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

    } 

,并使用类似的这种 '建筑' 功能:

static void Main(string[] args) 
    { 
     string cond1 = "hi"; 
     string cond2 = "lo"; 
     string cond3 = null; 
     var pr = new Predicate<Widget>((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); 
     } 
+0

不编译。 – Timwi 2010-09-21 13:59:24

+0

另外,更改逻辑。 OP检查所有非空条件,这只检查第一个。 OP还表示,条件是字符串,而这将它们视为布尔值。 – curveship 2010-09-21 14:19:46

+0

即使您确实修复了编译错误(字符串不能隐式转换为bool),该版本的程序与原始版本的语义也有很大不同。这个版本找到了可以测试并且仅使用它的第一个条件;原始版本应用了所有可能的条件。 – 2010-09-21 14:21:07

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

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

public List<Widget> 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(); 
} 

编辑:语法

+0

难以理解。但美丽的代码。 – Sagi 2015-12-06 17:18:53

+1

这是最好的解决方案,并将在一个SQL语句中执行。 – cmartin 2016-01-22 12:59:05

+1

这是更好的解决方案,用于指出ToList部分的+1。 – 2016-08-04 20:09:05

我们可以用很简单的方法如下图所示。

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