正如您所提到的,您需要接受Expression
在你的函数中,而不是Func
,以便 EF 能够实际翻译查询。
您需要的是组合表达式的能力,就像组合函数一样:
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
this Expression<Func<T, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
return Expression.Lambda<Func<T, TResult>>(
second.Body.Replace(second.Parameters[0], first.Body),
first.Parameters[0]);
}
这依赖于以下方法将一个表达式的所有实例替换为另一个表达式:
public 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 ex)
{
if(ex == from) return to;
else return base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
现在你可以很容易地编写你的方法:
public static IQueryable<T> Search<T>(this IQueryable<T> query,
Expression<Func<T, string>> selector,
string phrase)
{
return query.Where(selector.Compose(search => search.Contains(phrase)));
}