如何构建兼容EF的针对任意类型使用Any方法的表达式调用
补全方案
你需要先构造Any方法内部的相等判断逻辑lambda,再传入Expression.Call,补全后的核心代码如下:
// 构造Any方法的内部参数 i => i == 实体属性值 var anyItemParameter = Expression.Parameter(propType, "i"); var equalExpression = Expression.Equal(anyItemParameter, memberExpression); var anyPredicate = Expression.Lambda(equalExpression, anyItemParameter); // 调用Enumerable.Any扩展方法 var anyCall = Expression.Call( type: typeof(Enumerable), methodName: "Any", typeArguments: new[] { propType }, // Any的泛型参数为当前校验的属性类型 arguments: new Expression[] { constantExpression, anyPredicate } ); // 包装为Where查询需要的「实体=>布尔值」格式lambda result = Expression.Lambda<Func<TModel, bool>>(anyCall, parameterExpression);
优化后的完整ToExpression方法
可以直接修改返回类型为强类型表达式树,更适配EF的Where方法入参要求:
public static Expression<Func<TModel, bool>> ToExpression<TModel>(Query query) { var propInfo = typeof(TModel).GetProperty(query.PropertyName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance); if (propInfo == null) return null; var propType = propInfo.PropertyType; var parameterExpression = Expression.Parameter(typeof(TModel), "m"); var memberExpression = Expression.Property(parameterExpression, propInfo); var constantExpression = GetConstantExpressionForType(propType, query.AnyValues); if (constantExpression == null) return null; // 构造Any内部相等判断逻辑 var anyItemParameter = Expression.Parameter(propType, "i"); var equalExpression = Expression.Equal(anyItemParameter, memberExpression); var anyPredicate = Expression.Lambda(equalExpression, anyItemParameter); // 调用Any方法 var anyCall = Expression.Call( typeof(Enumerable), "Any", new[] { propType }, constantExpression, anyPredicate ); return Expression.Lambda<Func<TModel, bool>>(anyCall, parameterExpression); }
EF兼容性说明
以上构造的表达式树完全符合EF6、EF Core的翻译规则,不会出现无法翻译的报错,运行效果和你手写的静态LINQ查询完全一致。
内容的提问来源于stack exchange,提问作者Erik Philips
相关产品推荐
相关产品推荐

