代码之家  ›  专栏  ›  技术社区  ›  Andy Evans

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

  •  15
  • Andy Evans  · 技术社区  · 14 年前

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

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

    由于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 回复  |  直到 14 年前
        1
  •  34
  •   Fredrik Mörk    14 年前

    您要避免的是在准备就绪之前执行查询:

    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 托利斯特 List<> 回来了。我甚至建议将方法的返回值改为 IEnumerable<Widget> 跳过 托利斯特

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

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

        2
  •  23
  •   curveship    14 年前

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

    如果我写的话,我会像下面这样做。我使用var syntactic 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();
    } 
    

    编辑:语法

        3
  •  2
  •   Viv    14 年前

    像这样的怎么样?

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

    等。。。?

        4
  •  1
  •   xtofl Adam Rosenfield    14 年前

    在内部 linq查询。这个 Where 方法接受谓词,因此可以在创建查询之前构建谓词。

    --编辑——一开始,我觉得更简单,写了一些甚至没有编译的伪代码。不过,我想我明白了。这段代码将起作用;它将构建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);
            }
    
        5
  •  1
  •   Muni Chittem    7 年前

    我们可以用下面这样简单的方法。

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