如何在实体框架对象的LINQ to Entities中使用谓词

时间:2013-10-27 09:49:14

标签: c# entity-framework linq-to-entities predicate linqkit

我在数据访问层中使用LINQ to Entities for Entity Framework对象。

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

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

我的意思是

Func<MyEntity, bool>

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

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

我得到了例外

  

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

that question中的解决方案建议使用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语句。

谢谢。

2 个答案:

答案 0 :(得分:43)

您不需要LinqKit来执行此操作。请记住使用

Expression<Func<MyEntity, bool>>

而不是

Func<MyEntity, bool>

这样的事情:

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

您必须使用Expression,因为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);
}

答案 1 :(得分:2)

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

  

对于LINQ场景,涉及实体框架的查询   将某些CLR方法映射到基础数据源上的方法   通过规范功能。 LINQ to Entities中的任何方法调用   未明确映射到规范函数的查询将   导致运行时抛出NotSupportedException异常

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

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

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

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