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

时间:2010-09-21 13:46:39

标签: c# linq

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

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

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

5 个答案:

答案 0 :(得分:30)

在准备好之前,您要避免的是实际执行查询:

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

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

答案 1 :(得分:23)

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

如果我正在写它,我会像下面这样做。我使用var syntatic sugar来保存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();
} 

编辑:语法

答案 2 :(得分:2)

这样的事情怎么样?

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

等...

答案 3 :(得分:1)

您实际上是在 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);
        }

答案 4 :(得分:1)

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

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