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 ...
... 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.
If you do not call ToList() and your final mapping to the DTO type, you can add Where clauses as you go, and build the results at the end: var query = from u in DataContext. Users where u. Division == strUserDiv && u.
Filter collections using Where clause in C#. A single query expression may have multiple where clauses.
In LINQ, we can use Where() clause in the query to define multiple conditions, as shown below. This is how we can use LINQ where clause filtering operator to filter data based on conditions.
The LINQ to Objects provider is used for in-memory collections, using the local query execution engine of LINQ. The code generated by this provider refers to the implementation of the standard query operators as defined on the Sequence pattern and allows IEnumerable<T> collections to be queried locally.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With