0

I need to pass property name to the "GetClientsByFilter()" method via string parameter "propertyName" and use this property in LINQ expression.

It is assumed that there is need to use reflection.

Do you have any idea what I have to use instead string that with comment "//pseudo code" below? Thanks.

public class Client
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

internal class DataLayer
{
  public static List<Client> GetClientsByFilter(string search, string propertyName)
  {
     //it's Entity Framework context
     using (var dbContext = new LibDbContext())
        {
            List<Client> clients;

                 clients = dbContext.Clients
                .Where(item => item.[propertyName].Contains(search)) // pseudo code
                .ToList();
        }
     return clients;
  }
}

3 Answers3

2

You can pass instead of property yet another lambda which gets the property value:

public static List<Client> GetClientsByFilter(string search, 
                                              Func<Client, string> propertyGetter)
{
  //it's Entity Framework context
  using (var dbContext = new LibDbContext())
  {
    List<Client> clients;

    clients = dbContext.Clients
                       .Where(item => propertyGetter(item).Contains(search))
                       .ToList();
  }
  return clients;
}

Unfortunately, this approach cannot be used when you get the property name from "outside" and cannot build the proper lambda for getting the value. In such case you can prepare a dictionary of lambdas for each property name.

If you want to use reflection, please see the answer here

Community
  • 1
  • 1
ie.
  • 5,982
  • 1
  • 29
  • 44
0

I have solved this problem like this:

    public static List<Client> GetClientsByFilter(string search, string propertyName)
    {
        using (var dbContext = new LibDbContext())
        {     
            List<Client> clients;

              switch (propertyName)
              {
                case "LastName":

                  clients = dbContext.Clients
                      .Where(item => item.LastName.Contains(search))
                      .ToList();
                break;

                case "FirstName":

                  clients = dbContext.Clients
                      .Where(item => item.FirstName.Contains(search))
                      .ToList();
                break;
              }
           return clients;
        } 

But I want to rewrite this code and will make it more clearly without copy/paste

0

This is an almost-duplicate question of "How do I create an expression tree to represent 'String.Contains("term")' in C#?." Marc's answer provides this bit of code to build an expression, which is what you are looking for:

static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
{
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var propertyExp = Expression.Property(parameterExp, propertyName);
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(propertyValue, typeof(string));
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);

    return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}

...and now using it from your method:

public static List<Client> GetClientsByFilter(string search, string propertyName)
{
   //it's Entity Framework context
   using (var dbContext = new LibDbContext())
   {
        List<Client> clients;

             clients = dbContext.Clients
            .Where(GetExpression<Client>(propertyName, search)) // Now using Marc's method
            .ToList();
    }
 return clients;

}

Since "GetExpression" is generic, you can easily reuse this for other types besides just Client. Consider renaming the method since "GetExpression" doesn't spell out your intent - maybe something like "GetPropertyContainsExpression". You might also consider adding some error handling to that method in case the value in propertyName is not a valid property on the type and when the property specified isn't of type string which probably wouldn't have a Contains method that takes a string. These sorts of errors might be hard to figure out from the exceptions the expression builder might throw at run time.

Community
  • 1
  • 1
devgeezer
  • 4,159
  • 1
  • 20
  • 26