如何在Entity Framework中动态构造Where Expression?

时间:2016-08-27 15:42:52

标签: entity-framework linq where-clause expression-trees

我已经了解了this answer如何在Entity Framework中动态创建OrderBy表达式。但是我也想建立一个动态的Where表达式。有点像这样:

public IEnumerable<InventoryItem> GetAll(string filterBy, object value)
{
  var results = new List<InventoryItem>();
  using (var db = new InventoryDb())
  {
    if (QueryHelper.PropertyExists<InventoryItem>(filterBy)) 
    {
      var query = db.rri_InventoryItems.WhereByProperty(filterBy, value); 

      foreach(var item in query.Where(expr))
      {
        results.Add(ConvertItem(item));
      }   
    }            
  }
  return results;
}

传入属性以过滤by和值作为ab对象。 Queryable有两种方法,哪里都有两个参数,所以我甚至不确定哪一个是正确的。

此时此刻我失去了一点点。我不确定如何重构原始 OrderByProerty 方法以提供 WhereByProperty 。我知道我在这里完全错了。我不知道该怎么做。

理想情况下,我希望通过提供可用于使用 ands 运算符构建查询的对象集合来进一步扩展此功能。

2 个答案:

答案 0 :(得分:6)

  

Queryable有两种方法,哪里都有两个参数,所以我甚至不确定哪一个是正确的。

您需要收到Expression<Func<T, bool>> predicate的人。

以下是如何动态构建类似于(T item) => item.Property == value的谓词:

public static partial class QueryableExtensions
{
    public static IQueryable<T> WhereEquals<T>(this IQueryable<T> source, string member, object value)
    {
        var item = Expression.Parameter(typeof(T), "item");
        var memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
        var memberType = memberValue.Type;
        if (value != null && value.GetType() != memberType)
            value = Convert.ChangeType(value, memberType);
        var condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
        var predicate = Expression.Lambda<Func<T, bool>>(condition, item);
        return source.Where(predicate);
    }
}

我试图以这样的方式编写它,以便您可以跳过代码以了解它的作用。可能需要解释的唯一一行是:

var memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);

这是一种处理obj.Prop1.Prop2等嵌套属性的简单方法。如果您不需要这样的功能,可以简单地使用它:

var memberValue = Expression.PropertyOrField(item, member);

答案 1 :(得分:1)

我还不需要嵌套属性。我稍微修改了你的代码并使其正常工作:

    public static IQueryable<T> WhereEquals<T>(
       this IQueryable<T> source, string propertyName, object value)
    {
        if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
            BindingFlags.Public | BindingFlags.Instance) == null)
        {
            return null;
        }

        ParameterExpression parameter = Expression.Parameter(typeof(T), "item");
        Expression whereProperty = Expression.Property(parameter, propertyName);
        Expression constant = Expression.Constant(value);
        Expression condition = Expression.Equal(whereProperty, constant);
        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(condition,parameter);
        return source.Where(lambda);
    }