问题描述
在我的宇宙存储中,我的物品有一组关键字。 我想进行查询,以过滤出列表中至少有一个关键字的项目。
我尝试了Intersect方法:
query = query.Where(x => x.Keywords.Intersect(research.Kewords).Any())
所以我尝试了PredicateBuilder方法:
var pred = PredicateBuilder.False<Item>();
foreach (var k in research.Keywords)
pred = pred.Or(x => x.Keywords.Contains(k));
query = query.Where(pred);
但是我得到了一个异常“不支持使用NodeType'Invoke'的表达式”
这是我的predicateBuilder:
public static Expression<Func<T,bool>> False<T>() { return f => false; }
public static Expression<Func<T,bool>> Or<T>(this Expression<Func<T,bool>> expr1,Expression<Func<T,bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2,expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T,bool>>
(Expression.OrElse(expr1.Body,invokedExpr),expr1.Parameters);
}
在Cosmos中是否有办法实现这一目标?还是我必须在查询结果之后过滤?
解决方法
我过去使用过类似的PredicateBuilder类,其实现与您展示的有所不同。我对此解释得不多,因为它可能是SO的缩写,而我却忽略了文档:)。
有了它,您应该能够使用显示的表单:
expression = PredicateBuilder.Or(expression,x.Keywords.Contains(k));
实施
public static class PredicateBuilder
{
public static Expression<Func<T,bool>> True<T>() { return f => true; }
public static Expression<Func<T,bool>> False<T>() { return f => false; }
public static Expression<Func<T,bool>> Or<T>(this Expression<Func<T,bool>> expr1,Expression<Func<T,bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0],expr1.Parameters[0]);
return Expression.Lambda<Func<T,bool>>(Expression.OrElse(expr1.Body,secondBody),expr1.Parameters);
}
public static Expression<Func<T,bool>> And<T>(this Expression<Func<T,bool>> expr2)
{
if (expr2 != null)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0],expr1.Parameters[0]);
return Expression.Lambda<Func<T,bool>>(Expression.AndAlso(expr1.Body,expr1.Parameters);
}
else
{
return expr1;
}
}
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);
}
}