30

我正在为我的数据访问层中的实体框架对象使用 LINQ to Entities。

我的目标是尽可能多地从数据库中过滤,而不将过滤逻辑应用于内存结果。

为此,业务逻辑层将谓词传递给数据访问层。

我是说

Func<MyEntity, bool>

所以,如果我直接使用这个谓词,比如

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.Where(x => isMatched(x));
}

我得到了例外

[System.NotSupportedException] --- {“LINQ to Entities 不支持 LINQ 表达式节点类型 'Invoke'。”}

该问题的解决方案建议使用LINQKit库中的 AsExpandable() 方法。

但同样,使用

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}

我得到了例外

无法将“System.Linq.Expressions.FieldExpression”类型的对象转换为“System.Linq.Expressions.LambdaExpression”类型

有没有办法在 LINQ to Entities 查询中使用谓词来查询实体框架对象,以便正确地将其转换为 SQL 语句。

谢谢你。

4

2 回答 2

57

您不需要 LinqKit 来执行此操作。只记得使用

Expression<Func<MyEntity, bool>>

代替

Func<MyEntity, bool>

像这样的东西:

public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
    return _Context.MyEntities.Where(predicate);
}

您必须使用表达式,因为 Linq to Entities 需要将您的 lambda 转换为 SQL。

当您使用 Func 时,您的 lambda 被编译为 IL,但在使用 Expression 时,它是 Linq to Entities 可以横向和转换的表达式树。

这适用于 Linq to Entities 可以理解的表达式。

如果它一直失败,那么您的表达式会执行 Linq to Entities 无法转换为 SQL 的操作。在那种情况下,我认为 LinqKit 不会有帮助。

编辑:

不需要转换。只需使用 Expression 参数定义方法 GetAllMatchedEntities 并以与 Func 参数相同的方式使用它。编译器完成其余的工作。

您可以通过三种方式使用 GetAllMatchedEntities。

1) 使用内联 lambda 表达式:

this.GetAllMatchedEntities(x => x.Age > 18)

2)将您的表达式定义为一个字段(也可以是一个变量)

private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)

3)您可以手动创建表达式。缩小是更多的代码,你错过了编译时检查。

public Expression<Func<MyEntity, bool>>  IsMatchedExpression()
{
    var parameterExpression = Expression.Parameter(typeof (MyEntity));
    var propertyOrField = Expression.PropertyOrField(parameterExpression, "Age");
    var binaryExpression = Expression.GreaterThan(propertyOrField, Expression.Constant(18));
    return Expression.Lambda<Func<MyEntity, bool>>(binaryExpression, parameterExpression);
}
于 2013-10-27T12:29:54.913 回答
4

Linq to Entities 中使用的方法必须由 Linq 提供程序进行规范映射才能工作。由于 Linq 提供程序(在您的情况下为 EF)无法将您的谓词映射到内部方法,因此它引发了错误。

对于 LINQ 方案,针对实体框架的查询涉及通过规范函数将某些 CLR 方法映射到基础数据源上的方法。LINQ to Entities 查询中未显式映射到规范函数的任何方法调用都将导致引发运行时 NotSupportedException 异常

来源:CLR 方法到规范函数映射 ( http://msdn.microsoft.com/en-us/library/bb738681.aspx )

您可以尝试采用已映射的那些方法并将它们链接到您的Linq表达式中,或使用存储过程。但在 EF 支持所有 CLR 之前,您将不得不寻找解决方法。

从好的方面来说,每个版本似乎都在规范列表中添加了更多内容。

值得一读的可能解决方法:http: //msdn.microsoft.com/en-us/library/dd456857.aspx

于 2013-10-27T10:36:44.577 回答