andrew mclaughlin
andrew mclaughlin

Reputation: 57

c# use string parameter to define what property to filter by in List of objects

I want to use the filterType parameter to define what property on the Stock object to Filter by.

[HttpGet("{searchText}/{filterType}")] 
public async Task<ActionResult<List<Stock>>> Get(string searchText, string filterType)
 {
    List<Stock> v = await this._context.StockView.Where(w => w.[filterType] == searchText).ToListAsync();

    return this.Ok(v);
 }

Is there a way of doing this whereby i can use a string parameter to define a property on the Object to restrict by?

Upvotes: 3

Views: 483

Answers (2)

phuzi
phuzi

Reputation: 13060

You could use an Expression Tree to dynamically build a Linq where clause to filter on dynamic property.

I know this is probably a lot to digest but, here goes. Replace StockItem with the type of the StockView DbSet

[HttpGet("{searchText}/{filterType}")] 
public async Task<ActionResult<List<Stock>>> Get(string searchText, string filterType)
{
    var queryableStockView = this._context.StockView;

    // w =>
    var param = Expression.Parameter(typeof(StockItem), "w");

    var propertyInfo = typeof(StockItem).GetProperty(filterType);
    if (propertyInfo == null)
        throw new Exception($@"Property ""{property}"" was not found");

    // w.[filterType]
    var left = Expression.Property(param, propertyInfo);

    // searchText
    var right = Expression.Constant(searchText, typeof(string));

    // w.[filterType] == searchText
    var expression = Expression.Equal(left, right);
    
    // Bring it all together
    // Where(w => (w.[filterType] == searchText))
    var whereExpression = Expression.Call(
        typeof(Queryable),
        nameof(System.Linq.Enumerable.Where),
        new Type[] { queryableStockView.ElementType },
        queryableStockView.Expression,
        Expression.Lambda<Func<StockItem, bool>>(expression, new ParameterExpression[] { param })
    );

    // Run query against the database                                     
    var filteredItems = queryableStockView.Provider.CreateQuery<StockItem>(whereExpression);

    var v = await filteredItems.ToListAsync();

    return this.Ok(v);
 }

The dynamically generated Linq Expression should get translated to SQL without any issues.

Upvotes: 5

Seabizkit
Seabizkit

Reputation: 2415

to do what you are wanting you would need to write a bunch of mapping code.(out of scope you would need to show what you have tried)

it would be easier to execute raw sql that way you can set the field dynamically.

alternatively you can setup your data to support your searching... see below.

[HttpGet("{searchText}/{filterType}")] 
public async Task<ActionResult<List<Stock>>> Get(string searchText, string filterType)
 {
    var v = await this._context.StockView
              .Where(x => x.Type == filterType 
                       && x.SearchField == searchText).TolistAsync();

    return this.Ok(v);
 }

Upvotes: 1

Related Questions