Dynamic Where clause lambdas in C#
I have a search form that looks like this:
The code behind the form looks like this:
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<div>
@Html.DropDownList("SelectedType", Model.TypeOptions)
@Html.DropDownList("SelectedSearch", Model.SearchOptions)
@Html.TextBoxFor(x => x.SearchTerm)
<input type="submit" value="Search" />
</div>
}
What I want to do is dynamically construct a lambda where clause from the return options. E.g. if the user selects "Process No" and "Contains" then the lambda would look like
model.DataSource = _db.InstrumentLists.Where(x => x.Process_No.Contains(SearchTerm));
Or if the user selects "PLC No" and "Equals" then the lambda would look like
model.DataSource = _db.InstrumentLists.Where(x开发者_JS百科 => x.PLC_No == SearchTerm);
I am trying to do this while avoiding a big case statement or an if stack, i.e. I don't want the following:
if (SelectedType == "Process No" And SelectedSearch = "Contains")
model.DataSource = _db.InstrumentLists.Where(x => x.Process_No.Contains(SearchTerm));
elseif (SelectedType == "Process No" And SelectedSearch = "Equals")
model.DataSource = _db.InstrumentLists.Where(x => x.Process_No == SearchTerm);
...
Essentially I want to pass a reference to a class property, something to specify the test type (i.e contains, equals, starts with, etc) and a search term to a function, or something along those lines, and get back a predicate to put into my Where clause. I want this function to work dynamically so I shouldn't have to modify it for every combination of property and test type.
Is this possible or is the only way to use Where with a string predicate parameter?
Edit: In case its important, I'm use EF for my data model so _db.InstrumentLists returns an ObjectSet<InstrumentList>
.
you have 2 options here:
make a "switch" based search method i.e. depending on the value of user selection executes a different Where and returns a DataSource
use Dynamic Linq and construct the
Where
from a string
EDIT - example for Dynamic Linq:
model.DataSource = _db.InstrumentLists.Where(SelectedType + " == @0", SearchTerm);
Make use of predicate butilder to construct your where clause dynamically.
Check this article for deatil : Dynamic query with Linq .
Example :
var predicate = PredicateBuilder.True();
if(!string.IsNullOrEmpty(txtAddress.Text))
predicate = predicate.And(e1 => e1.Address.Contains(txtAddress.Text));
if (!string.IsNullOrEmpty(txtEmpId.Text))
predicate = predicate.And(e1 => e1.Id == Convert.ToInt32(txtEmpId.Text));
EmployeeDataContext edb= new EmployeeDataContext();
var emp = edb.Employees.Where(predicate);
grdEmployee.DataSource = emp.ToList();
grdEmployee.DataBind();
From the top of my head (I can't try it right now...):
public bool GetComparativeFunction(String property, SearchModel options)
{
if (options.SelectedSearch == "Contains") return property.Contains(options.SearchTerm);
if (options.SelectedSearch == "Equals") return property.Equals(options.SearchTerm);
return false; //default option
}
public Expression<Func<InstrumentLists, bool>> GetLambdaExpressionFromFilter(SearchModel options)
{
if (options.SelectedType == "Process_No")
return p => GetComparativeFunction(p.Process_No, options);
if (options.SelectedType == "PLC_No")
return p => GetComparativeFunction(p.PLC_No, options);
return p => true; //default option
}
Then in your query:
model.DataSource = _db.InstrumentLists.Where(GetLambdaExpressionFromFilter(Model));
I'm not sure it works with an IQueryable<> but you can always remove the Expression<> part if you can work with an IEnumerable<>
精彩评论