我正在尝试编写通用过滤器。 此过滤器几乎用于我的数据库中的每个表。我需要一个通用的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));
我收到此错误:
我在这里做错了什么?
如果iCompanyId == filterModel.SelectedCompanyId
这就是我调用过滤器的方式:
telematicDevices.ApplyFilterModel(model.FilterDTO);
其中telematicDevices是来自DB(实体框架)的IQueryable
答案 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);
}
filterModel.SelectedCompanyId
属性。这意味着使用Expression.Equals
传递投影属性和表示值的常量来比较它。Where
代替Equals
进行Expression.Call
通话。 (或者,就此而言,只需调用Where
作为方法,而不是构建表示该调用的表达式,因为它将通过其实现将自身表示为表达式。)而且假设你不想让你的生活轻松而且只是write out the implementation statically这不仅容易,而且还允许静态打字。