Luuk Wuijster
Luuk Wuijster

Reputation: 6878

Dynamic Linq Query where

I have a combobox and a Textbox. I can select a column in the combobox and then search for the thing.

So if I select "country" and type in the Textbox "Netherlands" (or a part of it) It should bring up all the customers that live in The Netherlands.

However, this does not work.

I have the country now hardcoded but how do I made that dynamic, so it's what I selected in the combobox?

This is my code:

CustomerContext context = new CustomerContext();

IQueryable<customer> customers = from x in context.customers
                                 where x.country.Contains(SearchBox.Text)
                                 select x;

Upvotes: 0

Views: 53

Answers (1)

John Wu
John Wu

Reputation: 52290

Brute force/straightforward:

IQueryable<customer> customers = from x in context.customers
                                 where (ComboBox.SelectedValue == "Country") && x.country.Contains(SearchBox.Text)
                                 ||    (ComboBox.SelectedValue == "City") && x.city.Contains(SearchBox.City)
                                 ||    (ComboBox.SelectedValue == "State") && x.state.Contains(SearchBox.State)
                                 select x;

There is absolutely nothing wrong with the above solution, but a lot of engineers will pooh pooh it because it doesn't seem maintainable or elegant or whatever. Harumph.

Fancy/elegant (a.k.a. complicated):

Note: You must arrange the items in the ComboBox in an order that matches the searches array.

static private readonly Func<customer, string>[] _searches;

static private Class() //Static constructor
{
    _searches = new Func<customer,string>[]
    {
        (c) => customer.City,
        (c) => customer.State,
        (c) => customer.Country 
    }
}

protected virtual void DoSearch() //Handles the search event
{
    var search = _searches[ComboBox.SelectedIndex];

    IQueryable<customer> customers = from x in context.customers
                                     where search(x).Contains(SearchBox.Text)
                                     select x;
}

The idea here is that you set up a series of lambdas in an array. Each lambda accepts a customer as input and returns one of the properties.

When the user triggers a search, you use the ordinal position in the combo box to choose a lambda expression corresponding to the property to be searched. You then use the lambda expression in your LINQ, causing the WHERE expression to search the property chosen by the lambda.

Using a dictionary

If you don't like the dependency between the array and the ordering of the combo box, you can use a dictionary instead:

static private readonly Dictionary<string, Func<customer, string>> _searches;

static private Class() //Static constructor
{
    _searches = new Dictionary<string, Func<customer,string>>();
    _searches.Add("City",    (c) => customer.City);
    _searches.Add("State",   (c) => customer.State);
    _searches.Add("Country", (c) => customer.Country);
}

protected virtual void DoSearch() //Handles the search event
{
    var search = _searches[ComboBox.SelectedValue];

    IQueryable<customer> customers = from x in context.customers
                                     where search(x).Contains(SearchBox.Text)
                                     select x;
}

Upvotes: 2

Related Questions