c# – 在函数中使用带有表达式的编译的LinQ查询

我想创建一个使用可重用的谓词的编译查询.举例说明:

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非常困难.重用是这种方法的最初目标……

最佳答案 问题是实体框架正在尝试检查由表示的表达式树

 (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所需要的.不幸的是,它有点难以考虑:(

点赞