LINQ Querying an Entity with Dynamic Field Names

c# dynamic-linq expression-trees lambda linq-to-entities

Question

In ASP.NET MVC, I have developed a dynamic search screen. Instead of showing every field in the view, I used reflection to extract the field names from the object and let the user choose the ones they wanted to search on.

The FieldName and the Value are sent to me in a FormCollection when the search result is sent back to the controller. I have no idea how many fields are being searched, and the FormCollection only includes user-selected fields.

When I query the database, I want to be able to take that field name and use it in my LINQ expression, for instance:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    List<People> searchResults = new List<People>();

    foreach (string key in fieldValueDictionary.Keys)
    {
         searchResults.Add(entities.People.Where(p => p.<use the key string as the fieldName> == fieldValueDictionary[key]));
    }

    return searchResults;
}

It would be p => p where I have "use the key string as the fieldName." FirstName is equal to fieldValueDictionary[key] with "FirstName" as the key. I've tried using Lambda Expression Trees and failed, but I've had some luck using Dynamic LINQ. The only other option is to do the following actions:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    IQueryable<People> results = entities.People;

    foreach (string key in fieldValueDictionary.Keys)
    {
         switch (k)
         {
             case "FirstName": results = results.Where(entities.People.Where(p => p.FirstName == k);
             case "LastName": results = results.Where(entities.People.Where(p => p.LastName == k);
             // Repeat for all 26 fields in table
         }
    }

    return results.ToList<People>();
}

UPDATE: The following postings represent my study on lambda expression trees:

dynamically generate OrderByDescending lambdas expressions using Linq.

Expression issue with parameters. Lambda()

LINQ: Executing and returning a lambda expression as a method's return value

I've managed to get a lambda to print "p => p.FirstName," but I can't get this to function in a where clause. Have any ideas? Below is my code:

MemberInfo member = typeof(People).GetProperty("FirstName");
ParameterExpression cParam = Expression.Parameter(typeof(People), "p");    
Expression body = Expression.MakeMemberAccess(cParam, member);        

var lambda = Expression.Lambda(body, cParam);
1
2
5/23/2017 12:30:40 PM

Accepted Answer

After much more Googling and trial-and-error, I unintentionally came upon another SO post that addresses the identical problem:

There is no "Where" method on the System type, which results in an invalid operation exception. Linq. The specified parameters are compatible with queryable.

Here is my functionally changed code:

        IQueryable query = entities.People;
        Type[] exprArgTypes = { query.ElementType };

        string propToWhere = "FirstName";            

        ParameterExpression p = Expression.Parameter(typeof(People), "p");
        MemberExpression member = Expression.PropertyOrField(p, propToWhere);
        LambdaExpression lambda = Expression.Lambda<Func<People, bool>>(Expression.Equal(member, Expression.Constant("Scott")), p);                            

        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), "Where", exprArgTypes, query.Expression, lambda);

        IQueryable q = query.Provider.CreateQuery(methodCall);

I should be able to adapt this to operate with any type with a few fairly simple tweaks.

Again, thanks for your responses. John and Ani Bowen

7
5/23/2017 12:19:48 PM

Popular Answer

Have you tried using PropertyInfo to get the value?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow