Las*_*son 7 c# filter expression-trees conditional-statements
我正在尝试构建一个过滤器表达式来过滤数据库中的数据.
我编写了以下扩展来动态构建表达式,具体取决于所选的过滤器参数:
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> leftExpression,
Expression<Func<T, bool>> rightExpression)
{
var invocationExpression = Expression.Invoke(rightExpression, leftExpression.Parameters.Cast<Expression>());
var andExpression = Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(leftExpression.Body, invocationExpression),
leftExpression.Parameters);
return andExpression;
}
Run Code Online (Sandbox Code Playgroud)
我正在以这种方式使用它:
Expression<Func<MyObject, bool>> expression = x => true;
if(MyFilter.SomeParam) {
expression = expression.And(x=>x.MyProperty == MyFilter.SomeParam);
}
Run Code Online (Sandbox Code Playgroud)
它适用于NHibernate,但是当我在Entity Framework 5中使用此代码时,它会失败,并显示以下异常消息:
LINQ to Entities不支持LINQ表达式节点类型"Invoke".
有一种解决方法从数据库中提取整个集合,然后通过IEnumerable.Where(Func<T1, T2> filterClause)它应用过滤条件,但它不需要所有数据只是为了获得一条记录,而Expression<Func<T1, T2>>表达式直接转换为SQL语句.
是否有任何简单的方法可以使此代码与Entity Framework一起使用?
从面向域的N层.NET 4.0示例应用程序中尝试此实现(还有规范模式的实现):
public static class ExpressionBuilder
{
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2348 次 |
| 最近记录: |