开发者

Dynamic Where clause lambdas in C#

开发者 https://www.devze.com 2023-03-31 02:22 出处:网络
I have a search form that looks like this: The code behind the form looks like this: @using (Html.BeginForm())

I have a search form that looks like this:

Dynamic Where clause lambdas in C#

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

0

精彩评论

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