所以我想根据一些简单的设置自动进行过滤。我的代码就是:
public ActionResult Index() // here I want to add filtering for Status I only want to show the active ones
{
IQueryable<Ticket> cases = db.Cases().AsQueryable();
cases = cases.EnablePaging().EnableFilterFor(x => x.Status);
return View(cases);
}
EnableFilterFor看起来像这样:
public static IQueryable<T> EnableFilterFor<T>(this IQueryable<T> queryable, Expression<Func<T, string>> keySelector)
{
string filterValue= "Active";
//Expression<Func<T, bool>> whereexpresion = keySelector.Compile() == "Active"
queryable = queryable.Where(
//here do the magic !! so that the result will be 'x=>x.Status == filterValue');
);
return queryable;
}
我搜索了很多东西,尝试了很多不同的东西但没有成功。我不得不将keySelector和filterValue组合起来工作(我需要一个Expression来使Where方法起作用)。任何帮助将不胜感激。
编辑:测试了两种解决方案后(谢谢你们两位!)我发现Poke拥有最好的解决方案。戳他的代码是唯一不会改变SQL生成方式的代码。当我看看Servy他生成的SQL时,它总是做一个EXTRA Sql select查询和一个EXTRA以及WHERE子句......不知道为什么:)答案 0 :(得分:2)
IQueryable.Where
需要Expression<Func<T, bool>>
,因此这将是我们需要构建的内容。由于我们想要从另一个表达式(Expression<Func<T, string>>
)中集成某些东西,我们必须“手动”构建表达式。
所以最后,我们要调用LambdaExpression.Lambda<Func<T, bool>>(…)
来获取Where
的表达式,但我们需要填写表达式主体:
// first, we reuse the parameter from the `keySelector` expression
ParameterExpression param = keySelector.Parameters[0];
// The body is now just an equality comparison of the `keySelector`
// body, and the constant `filterValue`
Expression body = Expression.Equal(keySelector.Body, Expression.Constant(filterValue));
// now we just need to create a lambda expression for that body with the
// saved parameter and it’s all done:
queryable = queryable.Where(Expression.Lambda<Func<T, bool>>(body, param));
答案 1 :(得分:2)
这里我们需要的是Compose
方法,用于表达式。它将使用一个表达式,该表达式使用一个值,另一个表达式在概念上将使用第一个表达式的结果作为其输入,从而生成新的输出。
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
它需要能够将一个表达式替换为另一个表达式,我们可以使用以下方法来完成:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
现在我们可以写:
public static IQueryable<T> EnableFilterFor<T>(
this IQueryable<T> queryable,
Expression<Func<T, string>> keySelector)
{
string filterValue= "Active";
return queryable.Where(keySelector.Compose(status => status == filterValue));
}