尝试编写通用过滤器IQueryable

时间:2015-02-17 20:42:20

标签: c# asp.net-mvc generics iqueryable

我正在尝试编写通用过滤器。 此过滤器几乎用于我的数据库中的每个表。我需要一个通用的Equals过滤器,这样我就可以应用于我的所有表而无需在任何地方重复我的代码

:我有以下代码:

public static IQueryable<T> ApplyFilterModel<T>(this IQueryable<T> source, FilterDTO filterModel)
{
    var type = typeof(T);

    if(filterModel.SelectedCompanyId != 0)
    {
        var property = type.GetProperty("iCompanyId");
        var parameter = Expression.Parameter(type, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        var resultExp = Expression.Call(typeof(Queryable), "Equals", new[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
        source = source.Provider.CreateQuery<T>(resultExp);
    }

    return source;
}

type.GetProperty("iCompanyId"); iCompanyId始终为Int32

所以当我调试并到达这一行时:

var resultExp = Expression.Call(typeof(Queryable), "Equals", new[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));

我收到此错误:

enter image description here

我在这里做错了什么?

如果iCompanyId == filterModel.SelectedCompanyId

,我需要过滤输入IQueryable

这就是我调用过滤器的方式:

telematicDevices.ApplyFilterModel(model.FilterDTO);

其中telematicDevices是来自DB(实体框架)的IQueryable

3 个答案:

答案 0 :(得分:3)

你能不申请.Where声明?

//Interface we need to access property
public interface ICompanySpecific
{
    public int iCompanyId { get; }
}

对于具有iCompanyId的每个对象,创建一个用于指定接口的分部类。

public partial class Person : ICompanySpecific
{
    //No code is needed because Person already has the iCompanyId property
}

现在您可以将它与Person或任何实现ICompanySpecific

的类型一起使用
public static IQueryable<T> ApplyFilterModel<T>(this IQueryable<T> source, FilterDTO filterModel)
    : where T: ICompanySpecific
{
    return source.Where(o => o.iCompanyId == filterModel.SelectedCompanyId);
}

答案 1 :(得分:1)

你可以尝试这样的事情:

public static IQueryable<T> ApplyFilterModel<T>(this IQueryable<T> source, FilterDTO filterModel)
{
var type = typeof(T);

if(filterModel.SelectedCompanyId != 0)
{
    var parameterExp = Expression.Parameter(type, "type");
    var propertyExp = Expression.Property(parameterExp, "iCompanyId");
    var constExp = Expression.Constant(filterModel.SelectedCompanyId, typeof(int)); // I'm assuming that SelectedCompanyId is an int.
    var equalExp = Expression.Equal(propertyExp, constExp);
    var lambda = Expression.Lambda<Func<T, bool>>(equalExp, constExp);
    source = source.Provider.Where(lambda);
}

return source;

}

答案 2 :(得分:0)

如果以静态方式写出,您创建的表达式将如下所示:

public static IQueryable<T> ApplyFilterModel<T>(this IQueryable<T> source,
    FilterDTO filterModel)
{
    return Queryable.Equals<T, int>(source, p => p.iCompanyId);
}

您真正想要做的是创建此动态版本:

public static IQueryable<T> ApplyFilterModel<T>(this IQueryable<T> source,
    FilterDTO filterModel)
{
    return Queryable.Where<T, int>(source, 
        p => p.iCompanyId == filterModel.SelectedCompanyId);
}
  1. 您需要让您的lambda实际比较您拥有的filterModel.SelectedCompanyId属性。这意味着使用Expression.Equals传递投影属性和表示值的常量来比较它。
  2. 使用Where代替Equals进行Expression.Call通话。 (或者,就此而言,只需调用Where作为方法,而不是构建表示该调用的表达式,因为它将通过其实现将自身表示为表达式。)
  3. 而且假设你不想让你的生活轻松而且只是write out the implementation statically这不仅容易,而且还允许静态打字。