C# 如何在LINQ中将谓词用于实体框架对象的实体

C# 如何在LINQ中将谓词用于实体框架对象的实体,c#,entity-framework,linq-to-entities,predicate,linqkit,C#,Entity Framework,Linq To Entities,Predicate,Linqkit,我在数据访问层中使用LINQ to实体作为实体框架对象 我的目标是尽可能多地从数据库中过滤,而不将过滤逻辑应用于内存中的结果 为此,业务逻辑层将谓词传递给数据访问层 我是说 Func<MyEntity, bool> Func 如果我直接使用这个谓词,比如 public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched) { return qry

我在数据访问层中使用LINQ to实体作为实体框架对象

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

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

我是说

Func<MyEntity, bool>
Func
如果我直接使用这个谓词,比如

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.Where(x => isMatched(x));
}
public IQueryable GetAllMatchedEntities(函数匹配)
{
返回qry=_Context.myenties.Where(x=>isMatched(x));
}
我得到了一个例外

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

中的解决方案建议使用库中的AsExpandable()方法

但同样,使用

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}
public IQueryable GetAllMatchedEntities(函数匹配)
{
返回qry=_Context.myenties.AsExpandable(),其中(x=>isMatched(x));
}
我得到了一个例外

无法强制转换类型为的对象 输入'System.Linq.Expressions.FieldExpression' 'System.Linq.Expressions.LambdaExpression'

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


谢谢。

Linq中使用的方法必须由Linq提供程序进行规范映射才能工作。因为Linq提供程序(在您的例子中是EF)无法将谓词映射到内部方法,所以它抛出了一个错误

对于LINQ场景,对实体框架的查询包括 将某些CLR方法映射到基础数据源上的方法 通过正则函数。LINQ中对实体的任何方法调用 未显式映射到规范函数的查询将 导致引发运行时NotSupportedException异常

源:CLR方法到规范函数映射()

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

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


作为一种可能的解决方法,值得一读:

您不需要LinqKit来完成这项工作。只要记住使用

Expression<Func<MyEntity, bool>>
2) 将表达式定义为字段(也可以是变量)

private只读表达式IsMatch=x=>x.Age>18;
…然后使用它
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);
}
公共表达式IsMatchedExpression()
{
var parameterExpression=Expression.Parameter(typeof(MyEntity));
var propertyOrField=Expression.propertyOrField(参数Expression,“Age”);
var binaryExpression=Expression.GreaterThan(propertyOrField,Expression.Constant(18));
返回表达式.Lambda(二进制表达式,参数表达式);
}

遗憾的是,我对表达几乎一无所知。例如,如果我有
public Boolean IsMatched(MyEntity entity){return entity.Age>18;}
作为我的谓词-如何将其转换为
表达式
?@user274947我已经用你给出的示例编辑了我的答案。我已经尝试了你的代码,但我收到编译错误
参数1:无法从“方法组”转换为“System.Linq.Expressions.Expression”
。看起来编译器正在等待
this.GetAllMatchedEntities(this.IsMatched(SOMETHING))
而不是
this.GetAllMatchedEntities(this.IsMatched)
。@user274947您是对的,您几乎可以用同样的方式使用它。我添加了一些如何使用GetAllMatchedEntities的示例。如何使用这种方法连接多个表?我不想干预,但公开
IQueryable
和表达式参数通常被认为是一个坏主意。最好将规范参数添加到
GetAllMatchedEntities
(如
int minimumAge
)并在方法内部构建查询。@GertArnold并非所有人都同意re'IQueryable'谢谢。这非常清楚。
public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
    return _Context.MyEntities.Where(predicate);
}
this.GetAllMatchedEntities(x => x.Age > 18)
private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)
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);
}