C# 如何在 LINQ to Entities 中为实体框架对象使用谓词
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19616711/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Howto use predicates in LINQ to Entities for Entity Framework objects
提问by bairog
I'm using LINQ to Entities for Entity Framework objects in my Data Access Layer.
我在数据访问层中将 LINQ to Entities 用于实体框架对象。
My goal is to filter as much as I can from the database, without applying filtering logic to in-memory results.
我的目标是尽可能多地从数据库中过滤,而不是将过滤逻辑应用于内存中的结果。
For that purpose Business Logic Layer passes a predicate to Data Access Layer.
为此,业务逻辑层将谓词传递给数据访问层。
I mean
我的意思是
Func<MyEntity, bool>
So, if I use this predicate directly, like
所以,如果我直接使用这个谓词,比如
public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
return qry = _Context.MyEntities.Where(x => isMatched(x));
}
I'm getting the exception
我得到了例外
[System.NotSupportedException] --- {"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."}
[System.NotSupportedException] --- {“LINQ to Entities 不支持 LINQ 表达式节点类型‘Invoke’。”}
Solution in that questionsuggests to use AsExpandable() method from LINQKitlibrary.
该问题中的解决方案建议使用LINQKit库中的AsExpandable() 方法。
But again, using
但是,再次使用
public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}
I'm getting the exception
我得到了例外
Unable to cast object of type 'System.Linq.Expressions.FieldExpression' to type 'System.Linq.Expressions.LambdaExpression'
无法将“System.Linq.Expressions.FieldExpression”类型的对象转换为“System.Linq.Expressions.LambdaExpression”类型
Is there way to use predicate in LINQ to Entities query for Entity Framework objects, so that it is correctly transformed it into a SQL statement.
有没有办法在 LINQ to Entities 查询实体框架对象中使用谓词,以便将其正确转换为 SQL 语句。
Thank you.
谢谢你。
采纳答案by andres.chort
You don't need LinqKit to do this. Just remember to use
您不需要 LinqKit 来执行此操作。只记得使用
Expression<Func<MyEntity, bool>>
instead of
代替
Func<MyEntity, bool>
Something like this:
像这样的东西:
public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
return _Context.MyEntities.Where(predicate);
}
You have to use Expression because Linq to Entities needs to translate your lambda to SQL.
您必须使用 Expression,因为 Linq to Entities 需要将您的 lambda 转换为 SQL。
When you use Func your lambda is compiled to IL but when using Expression it is an expression tree that Linq to Entities can transverse and convert.
当您使用 Func 时,您的 lambda 被编译为 IL,但当使用 Expression 时,它是一个表达式树,Linq to Entities 可以横向和转换。
This works with expressions that Linq to Entities understands.
这适用于 Linq to Entities 理解的表达式。
If it keeps failing then your expression does something that Linq to Entities can not translate to SQL. In that case I don't think LinqKit will help.
如果它一直失败,那么您的表达式会执行一些 Linq to Entities 无法转换为 SQL 的操作。在那种情况下,我认为 LinqKit 不会有帮助。
Edit:
编辑:
There is no conversion needed. Just define the method GetAllMatchedEntities with an Expression parameter and use it in the same way you would with a Func parameter. The compiler does the rest.
不需要转换。只需使用 Expression 参数定义方法 GetAllMatchedEntities 并以与使用 Func 参数相同的方式使用它。编译器完成剩下的工作。
There are three ways you can use GetAllMatchedEntities.
您可以通过三种方式使用 GetAllMatchedEntities。
1) With an inline lambda expression:
1) 使用内联 lambda 表达式:
this.GetAllMatchedEntities(x => x.Age > 18)
2) Define your Expression as a field (can be a variable also)
2)将您的表达式定义为一个字段(也可以是一个变量)
private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)
3) You can create your expression manually. The downsize is more code and you miss the compile-time checks.
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);
}
回答by Gayot Fow
Methods used in Linq to Entities must be canonically mapped by the Linq provider in order to work. Since the Linq provider, EF in your case, was unable to map your predicate to an internal method, it threw an error.
Linq to Entities 中使用的方法必须由 Linq 提供程序规范映射才能工作。由于 Linq 提供程序(在您的情况下为 EF)无法将您的谓词映射到内部方法,因此它引发了错误。
For LINQ scenarios, queries against the Entity Framework involve mapping certain CLR methods to methods on the underlying data source through canonical functions. Any method calls in a LINQ to Entities query that are not explicitly mapped to a canonical function will result in a runtime NotSupportedException exception being thrown
对于 LINQ 方案,针对实体框架的查询涉及通过规范函数将某些 CLR 方法映射到基础数据源上的方法。未显式映射到规范函数的 LINQ to Entities 查询中的任何方法调用都将导致抛出运行时 NotSupportedException 异常
Source: CLR Method to Canonical Function Mapping (http://msdn.microsoft.com/en-us/library/bb738681.aspx)
来源:CLR 方法到规范函数映射 ( http://msdn.microsoft.com/en-us/library/bb738681.aspx)
You can try to take those methods that AREmapped and chain them into your Linq expression, or use a stored procedure. But until EF supports all of the CLR, you will be left with having to find a work-around.
你可以尝试采取那些方法ARE映射并连锁到你的LINQ表达式,或者使用存储过程。但是,在 EF 支持所有 CLR 之前,您将不得不寻找解决方法。
On the plus side, each release seems to add a bit more to the canonical list.
从好的方面来说,每个版本似乎都为规范列表添加了更多内容。
Worth reading as a possible work-around: http://msdn.microsoft.com/en-us/library/dd456857.aspx
值得一读作为一种可能的解决方法:http: //msdn.microsoft.com/en-us/library/dd456857.aspx