我想创建一个使用可重用的谓词的编译查询。举例来说明这一点:
ObjectContext.Employees.Where(EmployeePredicates.CustomerPredicate)
EmployeePredicates是一个静态类,其属性CustomerPredicate如下所示:
public static Expression<Func<Employee, bool>> CustomerPredicate
{
get
{
return t => t.CustomerId == 1;
}
}
这可以按预期工作。 但是,在大多数情况下,您希望将参数传递给Expression。为此,我必须将属性更改为静态函数:
public static Expression<Func<Employee, bool>> CustomerPredicate(int id)
{
return t => t.CustomerId == id;
}
我可以这样使用:
ObjectContext.Employees.Where(EmployeePredicates.CustomerPredicate(id))
这有效,但现在是棘手的部分。我想编译这个查询... Visual Studio不会给我任何编译错误,但是当我运行这个例子时,在运行时抛出以下异常:
Internal .NET Framework Data Provider error 1025
我们在同一页面上就是完整的代码,它给了我一个例外:
var _compiledQuery = CompiledQuery.Compile<AdventureWorksEntities, int, IQueryable<Employee>>(
(ctx, id) =>
(ctx.Employee.Where(EmployeePredicates.CustomerPredicate(id))
));
有没有人知道为什么会抛出这个异常?我采用这种方式从http://www.albahari.com/nutshell/linqkit.aspx开始工作。任何帮助将不胜感激。
谢谢Jon,
您描述的方法的问题在于,将谓词链接在一起将变得非常困难。如果我需要将此谓词与另一个使用特定名称过滤员工的谓词相结合,该怎么办?然后你最终会有很多选择来传递参数。
(ctx, id, name) =>
(ctx.Employee.Select(emp => new {emp, id})
.Where(EmployeePredicates.CustomerPredicate(id))
.Select(emp => new {emp, name})
.Where(EmployeePredicates.NamePredicate(name))
当你在连接表上工作时,情况变得更糟。
(ctx, id, name) =>
(ctx.Employee
.Join(ctx.Contact, e=> e.ContactId, c => c.Id), (emp, cont) => new Container<Employee, Customer> {Employee = emp, Contact = cont})
.Where(EmployeePredicates.CustomerPredicate(id))
.Where(EmployeePredicates.NamePredicate(name))
.Select(t => new EmployeeDTO {Name = t.cont.Name, Customer = e.emp.Customer})
因为每个Where()都对T类型的东西进行操作并返回类型为T的东西,所以上面代码中的WherePredicates必须适用于Container类型。这使得重用Predicates非常困难。重用是这种方法的最初目标......
答案 0 :(得分:2)
问题是实体框架正在尝试检查由
表示的表达式树 (ctx, id) => (ctx.Employee.Where(EmployeePredicates.CustomerPredicate(id))
它无法做到这一点,因为它不知道EmployeePredicates.CustomerPredicate
做了什么。
至于最好的解决方案......我不确定。基本上它必须在查询编译时知道 完整查询的样子,只需使用参数的占位符。
我怀疑最佳解决方案将包含以下内容:
public static Expression<Func<Employee, int, bool>> CustomerPredicate()
{
return (t, id) => t.CustomerId == id;
}
......因为这会将抽象提升一级;它为您提供了一个表达式树,它使用id
作为ParameterExpression
,这是您构建适当的表达式树以调用CompileQuery
所需要的。不幸的是,它有点难以思考:(