C# linq - Change the selected field at runtime

c# dynamic expression-trees linq

Question

I have an object Orders (Order, Product, Cost, Price, Client, Day). I am retrieving a lot of records from the database and to facilitate filtering, I need to pouplate DropDownLists with the distinct values retrieved so the user can select only specific dates or specific products or even a specific price. The IDs of the DropDownList are created as "ddl_" + name of the concerned field.

What I'd like is to be able to define a simple array like this:

public string[] filterArray = new string[] { "Order", "Product", "Cost", "Price", "Client", "Day" };

Then call a BindDLLs method:

foreach (string filterName in filterArray)
{
    // Find the ddl to populate
    DropDownList ddl = (DropDownList)this.FindControl("ddl_" + filterName);
    // Get the data for that ddl only (use filterName in the select...)
    var query = (from items in results select items.filterName.ToString()).Distinct();

    // Populate the ddl (not complete code...)
    foreach (var item in query)
    {
        ddl.Items.Add(item...);
    }
}

My problem is that I find plenty of documentation on how to modify the WHERE or GROUP BY or any other parts of linq statements at run-time. I just don't find any on how to change dynamically the field I want to retrieve.

Is there an easy way to do this? Thank you. Yipi

Edit:

List<Orders> results = OrdersService.GetOrders();

public class Orders
{
    [DataMember]
    public DateTime? Day
    [DataMember]
    public int? Order
    [DataMember]
    public int? Product
    [DataMember]
    public int? Cost
    [DataMember]
    public int? Price
    [DataMember]
    public int? Client
    [DataMember]
}

Popular Answer

You can solve this problem by building the lambda expression by hand.

The query you currently use can be changed to use method chains syntax and will then look like this:

var query = results.Select(item => item.<filterName>.ToString()).Distinct();

Now we need to create the lambda expression that is passed to Distinct ourselves.

This can be achieved using the following method:

Expression<Func<YourResultType, string>> CreateExpression(string propertyName)
{
    var itemExpression = Expression.Parameter(typeof(YourResultType), "item");
    var propertyExpression = Expression.Property(itemExpression, propertyName);
    var toStringExpression = Expression.Call(propertyExpression,
                                             "ToString", null);
    return Expression.Lambda<Func<YourResultType, string>>(toStringExpression, 
                                                           itemExpression);
}

Now we can change the query to this:

var query = results.Select(CreateExpression(filterName)).Distinct();

Please note that you need to change YourResultType to the type of the instances in your results variable. Also, if you are not querying a database but an in memory list, you need to change the query to this:

var query = results.Select(CreateExpression(filterName).Compile()).Distinct();


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why