我尝试查询(对实体EF Core的查询)导航属性集合,因此我使用any()像这样:
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(p => p.myprop == myvar );
它工作得很好,但是现在我想构造谓词,而不是直接在查询中定义它。 所以我做:
Func<T, bool> mypredicate = (p => p.myprop == myvar);
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(mypredicate);
(我用实体名称替换了T)
但这会产生错误:无法将类型为“ System.Linq.Expressions.TypedParameterExpression”的对象转换为类型为“ System.Linq.Expressions.LambdaExpression”。
我如何构造我的谓词以在Any()集合上使用它? 谢谢
答案 0 :(得分:0)
例如以下行:
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(p => p.myprop == 1));
在编译时将被编译为如下内容:
var xParameter = Expression.Parameter(typeof(Entity1), "x");
var pParameter = Expression.Parameter(typeof(Entity2), "p");
var anyMethod =
typeof(Enumerable)
.GetMethods()
.Single(x => x.Name == "Any" && x.GetParameters().Length == 2)
.MakeGenericMethod(typeof(Entity2));
var anyCondition = Expression.Lambda<Func<Entity2, bool>>(
Expression.Equal(
Expression.Property(
pParameter,
typeof(Entity2).GetProperty("myprop").GetMethod),
Expression.Constant(1, typeof(int))),
pParameter);
var query = context.MyTable.Where(
Expression.Lambda<Func<Entity1, bool>>(
Expression.Call(
null,
anyMethod,
new Expression[] {
Expression.Property(
xParameter,
typeof(Entity1).GetProperty("mycollectionproperties").GetMethod),
anyCondition
}),
xParameter));
这称为表达式树。有关更多详细信息,请参见此参考资料: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/
尽管Any
方法使用了Func
,但是在构造表达式树时,请注意,Expression<Func<Entity2, bool>>
方法中使用了表达式(Any
)。
C#似乎没有办法给Any
方法一个表达式而不是Func
,即使整个事情都是一个表达式树(我的意思是像您想要实现的目标。
实现所需目标的最明显方法是使用本文中的代码,并将anyCondition
变量替换为要用于Any
内部条件的任何表达式。
另一种方法是“正常”地构造表达式树的一部分,并将null
传递给Any
方法,然后使用表达式访问者用表达式替换null
。这种访客的样子如下:
public class AnyMethodArgumentReplacingVisitor : ExpressionVisitor
{
private readonly Expression expression;
public AnyMethodArgumentReplacingVisitor(Expression expression)
{
this.expression = expression;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "Any")
{
return Expression.Call(node.Object, node.Method, node.Arguments[0], expression);
}
return base.VisitMethodCall(node);
}
}
这是您将如何使用它:
Expression<Func<Entity2, bool>> predicate =
a => a.myprop == 2;
Expression<Func<Entity1, bool>> expression =
b => b.mycollectionproperties.Any(null);
var expression2 =
(Expression<Func<Entity1, bool>>)
new AnyMethodArgumentReplacingVisitor(predicate).Visit(expression);
请注意,此类访问者会将调用替换为任何Any
方法。它还假定仅使用带有谓词的Any
的重载。 Any
的另一个重载不带谓词。如果需要使用它,则需要调整代码。
答案 1 :(得分:-1)
在我看来,您的问题出在您对
的定义中Func<T, bool> mypredicate = (p => p.myprop == myvar);
您不应使用 T ,而应使用 mycollectionproperties
假设属性 mycollectionproperties 被定义为类似的内容
....
public IQueryable<YourType> mycollectionproperties { get; set; }
....
然后,您应将 mypredicate 声明为
Func<YourType, bool> mypredicate = (p => p.myprop == myvar);
您可以在.NetFiddle
上看到一个有效的示例。