开发者

Implementing conditional 'if' statements within a LINQ queries 'where' statement

开发者 https://www.devze.com 2023-01-17 04:24 出处:网络
I\'m trying to figure out a way of querying an object in my datamodel and include only those parameters that are not null.Like below:

I'm trying to figure out a way of querying an object in my datamodel and include only those parameters that are not null. Like below:

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 ...
                           开发者_Python百科     ... if cond2 != null w.condition2 == cond2 ...
                                ... if cond3 != null w.condition3 == cond3 ...
                            select w).ToList();
    return widgets;
}

Since the widgets table can get very large, I'd like to avoid doing this:

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

I've looked at several example but don't really see anything that matches what I need to do.


What you want to avoid is actually executing the query until you are ready:

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

Note how the ToList calls are removed. The query is not executed until you start iterating over it. Invoking ToList will force that to happen, so that the result can be put into a List<> and returned. I would even suggest to change the return value of the method to IEnumerable<Widget> and skipping the ToList call in the end:

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

That way the calling code gets to decide when to execute the query (it may even add more conditions before doing so).


Use an "or gate": preface every widget condition test with an "||" and a check to see if we're using that condition or not. If we're not, the second half of the "or" isn't evaluated. That's why it's a gate -- we don't go any further if the first part evaluates to true.

If I were writing it, I'd do it like below. I used the var syntatic sugar to hold LINQ query and moved the ToList() to the end.

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

edit: grammar


How about something like this?

        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...?


You're actually asking for a dispatcher within the linq query. The Where method takes a predicate, so you can build your predicate before creating the query.

-- EDIT -- at first, I thought it easier, wrote some pseudo code that didn't even compile. Now, howver, I think I got the point. This code will work; it separates building the where clause from applying it.

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

    }

and use this 'building' functionality like that:

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

I tested it with a little helper array:

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


we can use very simple way like below.

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号