使用LinqKit PredicateBuilder进行相关模型(EF Core)
我想使用LinqKit的PredicateBuilder并将谓词传递给相关模型的.Any方法。
所以我想构建一个谓词:
var castCondition = PredicateBuilder.New(true); if (movies != null && movies.Length > 0) { castCondition = castCondition.And(c => movies.Contains(c.MovieId)); } if (roleType > 0) { castCondition = castCondition.And(c => c.RoleId == roleType); }
然后使用它来过滤与谓词中的模型有关的模型:
IQueryable result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition)); return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();
但这会导致System.NotSupportedException: Could not parse expression 'n.CastInfo.Any(Convert(__castCondition_0, Func``2))': The given arguments did not match the expected arguments: Object of type 'System.Linq.Expressions.UnaryExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'.
我看到类似的问题和答案建议使用。 .Compile
。 或者另外一个构建额外谓词的问题。
所以我试着使用额外的谓词
var tp = PredicateBuilder.New(true); tp = tp.And(n => n.CastInfo.Any(castCondition.Compile())); IQueryable result = _context.Name.AsExpandable().Where(tp);
或直接使用编译
IQueryable result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition.Compile()));
但我有一个关于编译的错误: System.NotSupportedException: Could not parse expression 'n.CastInfo.Any(__Compile_0)'
那么是否可以将PredicateBuilder的结果转换为Any
?
注意:我能够构建组合表达式的所需行为,但我不喜欢我需要额外的变量。
System.Linq.Expressions.Expression<Func> castExpression = (c => true); if (movies != null && movies.Length > 0) { castExpression = (c => movies.Contains(c.MovieId)); } if (roleType > 0) { var existingExpression = castExpression; castExpression = c => existingExpression.Invoke(c) && c.RoleId == roleType; } IQueryable result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castExpression.Compile())); return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();
所以我假设我只是想念建筑师。
关于版本的更新:我使用dotnet core 2.0和LinqKit.Microsoft.EntityFrameworkCore 1.1.10
查看代码,可以假设castCondition
变量的类型是Expression
(就像在早期版本的PredicateBuilder
)。
但如果是这种情况,则n.CastInfo.Any(castCondition)
甚至不应该编译(假设CastInfo
是一个集合导航属性,因此编译器将命中Enumerable.Any
,它需要Func
,而不是Expression
)。 那么这里发生了什么?
在我看来,这是C#隐式操作符滥用的一个很好的例子。 PredicateBuilder.New
方法实际上返回一个名为ExpressionStarter
的类,它有许多模拟Expression
方法,但更重要的是, 隐式转换为Expression
和Func
。 后者允许该类用于顶级Enumerable
/ Queryable
方法,以替换相应的lambda func / expression。 但是,它也可以防止在表达式树中使用时出现编译时错误 – 编译器会发出类似n.CastInfo.Any((Func
,这当然会在运行时导致exception。
LinqKit AsExpandable
方法的全部思想是允许通过自定义Invoke
扩展方法“调用”表达式,然后在表达式树中“展开”。 所以回到开头,如果变量类型是Expression
,那么预期的用法是:
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.Invoke(c)));
但是由于之前解释的原因,现在这不能编译。 所以你必须先将它转换为查询之外的Expression
:
Expression> castPredicate = castCondition;
然后使用
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castPredicate.Invoke(c)));
要么
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(castPredicate.Compile()));
为了让编译器推断表达式类型,我将创建一个这样的自定义扩展方法:
using System; using System.Linq.Expressions; namespace LinqKit { public static class Extensions { public static Expression> ToExpression(this ExpressionStarter expr) => expr; } }
然后简单地使用
var castPredicate = castCondition.ToExpression();
它仍然必须在查询之外完成,即以下操作不起作用:
_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.ToExpression().Invoke(c)));
- 如何在net-core 2.0中手动解析JSON字符串
- 为什么Finalize / Destructor示例在.NET Core中不起作用?
- validationJWT令牌后访问dotnetcore中间件
- .Net核心/控制台应用程序/配置/ XML
- 如何在.NET Core项目中引用.NET Framework项目?
- .net核心中的WCF(TransportWithMessageCredential)
- .NET Core IServiceScopeFactory.CreateScope()vs IServiceProvider.CreateScope()扩展
- 在EF Core中添加一对一关系时迁移数据?
- UWP NetworkConnectionChanged事件