简体   繁体   中英

How to give property name in string in lambda expression?

I want to write a query in .net core using ef. Now the issue is, I am getting the property name in parameter and I want to put condition on that property ie

  public IQueryable<MyModel> Generate(string property, IQueryable<MyModel> query)
  {
    query = query.Where(a => a.property.ToLower() != null);
  }

MyModel:

public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }

Method Calling:

var query = Generate(MyModel.Property2, query);

I know this is possible using reflection but that has some performance impacts. So is there any better approach?

Can you use Func<MyModel, string> as param?

public IQueryable<MyModel> Generate(Func<MyModel, string> propertySelector, IQueryable<MyModel> query)
{
   query = query.Where(a => propertySelctor(a).ToLower() != null);
}

And use like:

var query = Generate(m => m.Property2, query);

EDIT after question clarification:

You could implement a generic extension method for IQueryable where the clause is dynamically built:

public static class QueryExtensions
{
    public static IQueryable<TModel> WhereNotNull<TModel>(this IQueryable<TModel> query, string propertyName)
    {
        var parameter = Expression.Parameter(typeof(TModel), "x");
        var body = Expression.PropertyOrField(parameter, propertyName);
        var comparison = Expression.NotEqual(body, Expression.Constant(null, typeof(object)));
        var lambda = Expression.Lambda<Func<TModel, bool>>(comparison, parameter);
        return query.Where(lambda);
    }
}

Call it like:

query = query.WhereNotNull(nameof(MyModel.Property1));

or

query = query.WhereNotNull("Property1");

EDIT after request for null or whitespace check on strings:

Example of calling string.IsNullOrWhiteSpace() on string properties:

public static IQueryable<TModel> WhereNotNull<TModel>(this IQueryable<TModel> query, string propertyName)
{
    var parameter = Expression.Parameter(typeof(TModel), "x");
    var body = Expression.PropertyOrField(parameter, propertyName);
    Expression<Func<TModel, bool>> lambda = null;
    if (body.Type == typeof(string))
    {
        var methodCall = Expression.Call(typeof(string), nameof(string.IsNullOrWhiteSpace), null, body);
        var nullOrWhiteSpaceComparison = Expression.Not(methodCall);
        lambda = Expression.Lambda<Func<TModel, bool>>(nullOrWhiteSpaceComparison, parameter);
    }
    else
    {
        var nullComparison = Expression.NotEqual(body, Expression.Constant(null, typeof(object)));
        lambda = Expression.Lambda<Func<TModel, bool>>(nullComparison, parameter);
    }
    return query.Where(lambda);
    }

If you (in some other context) want to combine multiple expressions you may use Expression.And(Expression left, Expression right) or Expression.Or(Expression left, Expression right) . Pass the unary/binary expression as parameters left and right.

You can do it like this:

public IQueryable<TModel> Generate<TModel, TProperty>(Func<TModel, TProperty> propertyFunc, IQueryable<TModel> query)
{
    return query.Where(a => propertyFunc(a) != null);
}

It will be a more flexible solution than Dmitry.

public IQueryable<MyModel> Generate(string property, IQueryable<MyModel> query)
{
    query = query.Where(a => EF.Property<string>(a, property) != null);
}

Reference: EF.Property(Object, String) Method

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM