C# 保持';LINQ表达式节点类型';调用&x27;在LINQ to实体';例外情况
我正在使用C#(包括Linq)开发一个web应用程序。我已经编写了一个通用方法来扩展任何实体的Get方法。但是,当我得到运行时异常“执行代码时,LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。代码如下:C# 保持';LINQ表达式节点类型';调用&x27;在LINQ to实体';例外情况,c#,.net,linq,entity-framework,C#,.net,Linq,Entity Framework,我正在使用C#(包括Linq)开发一个web应用程序。我已经编写了一个通用方法来扩展任何实体的Get方法。但是,当我得到运行时异常“执行代码时,LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。代码如下: using System.Linq; using System.Linq.Expressions; using LinqKit; public static class ServiceExtension { public static IEnumerab
using System.Linq;
using System.Linq.Expressions;
using LinqKit;
public static class ServiceExtension
{
public static IEnumerable<T> GetActive<T>(this ICrudService<T> crudService, Expression<Func<T, bool>> where)
where T : class, IDeletable
{
return crudService.Get(where.And(w => !w.IsDeleted));
}
}
使用System.Linq;
使用System.Linq.Expressions;
使用LinqKit;
公共静态类服务扩展
{
公共静态IEnumerable GetActive(此ICrudService crudService,表达式where)
其中T:类,可识别
{
返回crudService.Get(where.And(w=>!w.IsDeleted));
}
}
有人能告诉我我做错了什么吗?您使用的是LinqKit,它只适用于调用了
AsExpandable()
的查询文件。这将包装基础查询提供程序,并将所有调用Invoke
(内部正在使用和
)转换为查询提供程序能够理解的内容
另一种选择是不使用LinqKit,而是使用以下版本的PredicateBuilder,它可以在不依赖于使用Invoke
的情况下调用和/或谓词表达式:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
我相信问题出在你的方法上。您可以使用静态表达式方法自己创建表达式
public static IEnumerable<T> GetActive<T>(this ICrudService<T> crudService, Expression<Func<T, bool>> where)
where T : class, IDeletable
{
var parameter = where.Parameters.FirstOrDefault();
var property = Expression.PropertyOrField(parameter, "IsDeleted");
var notProperty = Expression.Not(property);
var andExpression = Expression.AndAlso(where.Body, notProperty);
var lambda = Expression.Lambda<Func<T, bool>>(andExpression, parameter);
return crudService.Get(lambda);
}
公共静态IEnumerable GetActive(此ICrudService crudService表达式,其中)
其中T:类,可识别
{
var parameter=where.Parameters.FirstOrDefault();
var property=Expression.PropertyOrField(参数“IsDeleted”);
var notProperty=Expression.Not(属性);
var andExpression=Expression.AndAlso(其中.Body,notProperty);
var lambda=Expression.lambda(andExpression,parameter);
返回crudService.Get(lambda);
}
塞维的回答很好,对我很有用。我已经拿了它,并对它进行了一些扩展/更改,然后将它添加到这个上面以回报一点
首先,我将True和False属性重命名为BaseAnd(而不是True)和BaseOr(而不是False)。主要是基于我如何使用它们以获得我想要的结果,这对我来说更容易理解
此外,我还添加了两个新的泛型函数:addtopredicateTypebasedOnIfandorr,它接受两个ref谓词,一个用于and,一个用于ors,并将根据是否应该是and向其中一个添加表达式。这只是为了减少代码重复,因为在应用程序运行之前,我的代码不知道应该是哪种类型
CombineOrprecatesWithandPredicates接受初始谓词表达式、and谓词表达式和or谓词表达式,并以sql逻辑方式(and list)和(or list)组合它们。这也是为了减少代码重复
希望这能帮助其他人
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> BaseAnd<T>() { return f => true; }
public static Expression<Func<T, bool>> BaseOr<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
public static Expression<Func<T, bool>> CombineOrPreicatesWithAndPredicates<T>(this Expression<Func<T, bool>> combinedPredicate,
Expression<Func<T, bool>> andPredicate, Expression<Func<T, bool>> orPredicate)
{
combinedPredicate = combinedPredicate ?? BaseAnd<T>();
if (andPredicate != null && orPredicate!=null)
{
andPredicate = andPredicate.And(orPredicate);
combinedPredicate = combinedPredicate.And(andPredicate);
}
else if (orPredicate!=null)
{
combinedPredicate = combinedPredicate.And(orPredicate);
}
else
{
combinedPredicate = combinedPredicate.And(andPredicate);
}
return combinedPredicate;
}
public static void AddToPredicateTypeBasedOnIfAndOrOr<T>(ref Expression<Func<T, bool>> andPredicate,
ref Expression<Func<T, bool>> orPredicate, Expression<Func<T, bool>> newExpression, bool isAnd)
{
if (isAnd)
{
andPredicate = andPredicate ?? BaseAnd<T>();
andPredicate = andPredicate.And(newExpression);
}
else
{
orPredicate = orPredicate ?? BaseOr<T>();
orPredicate = orPredicate.Or(newExpression);
}
}
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
公共静态类谓词生成器
{
公共静态表达式BaseAnd(){return f=>true;}
公共静态表达式BaseOr(){return f=>false;}
公共静态表达式或(
这个表达式expr1,
表达式expr2)
{
var secondBody=expr2.Body.Replace(expr2.Parameters[0],expr1.Parameters[0]);
返回表达式.Lambda
(Expression.OrElse(expr1.Body,secondBody),expr1.Parameters);
}
公共静态表达及其应用(
这个表达式expr1,
表达式expr2)
{
var secondBody=expr2.Body.Replace(expr2.Parameters[0],expr1.Parameters[0]);
返回表达式.Lambda
(表达式AndAlso(expr1.Body,secondBody),expr1.Parameters);
}
公共静态表达式替换(此表达式,
表达式searchEx、表达式replacex)
{
返回新的ReplaceVisitor(searchEx,replaceEx)。访问(表达式);
}
公共静态表达式CombineOrpregatesWithandPredicates(此表达式combinedPredicate,
表达式和谓词,表达式或谓词)
{
combinedPredicate=combinedPredicate??BaseAnd();
if(andPredicate!=null&&orPredicate!=null)
{
andPredicate=andPredicate.和(或预测);
combinedPredicate=combinedPredicate.And(andPredicate);
}
否则如果(或预测!=null)
{
combinedPredicate=combinedPredicate.And(或Predicate);
}
其他的
{
combinedPredicate=combinedPredicate.And(andPredicate);
}
返回组合谓词;
}
公共静态void addtopreditatetypebasedonifandorr(ref表达式和谓词,
ref表达式或预测表达式、表达式newExpression、bool isAnd)
{
如果(isAnd)
{
andPredicate=andPredicate??BaseAnd();
andPredicate=andPredicate.And(新表达式);
}
其他的
{
orPredicate=orPredicate??BaseOr();
orPredicate=orPredicate.或(新表达式);
}
}
}
内部类ReplaceVisitor:ExpressionVisitor
{
私有只读表达式from、to;
公共访问者(表达式from、表达式to)
{
this.from=from;
这个;
}
公共重写表达式访问(表达式节点)
{
返回节点==从?到:基本访问(节点);
}
}
您能告诉我们Get
-方法做什么吗?我正在做的一个调用示例是Service.GetActive(x=>x.Id>10)
。我是否可能调用不正确?这里没有关于调用的内容。错误是关于另一行的。可能在Get
方法或where
表达式中?您是否考虑过Linq to实体不支持调用?我认为错误信息是完全正确的。LINQtoSQL确实支持它,但不支持LINQtoEntities。您必须调用invoke somewherepublic static class PredicateBuilder
{
public static Expression<Func<T, bool>> BaseAnd<T>() { return f => true; }
public static Expression<Func<T, bool>> BaseOr<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
public static Expression<Func<T, bool>> CombineOrPreicatesWithAndPredicates<T>(this Expression<Func<T, bool>> combinedPredicate,
Expression<Func<T, bool>> andPredicate, Expression<Func<T, bool>> orPredicate)
{
combinedPredicate = combinedPredicate ?? BaseAnd<T>();
if (andPredicate != null && orPredicate!=null)
{
andPredicate = andPredicate.And(orPredicate);
combinedPredicate = combinedPredicate.And(andPredicate);
}
else if (orPredicate!=null)
{
combinedPredicate = combinedPredicate.And(orPredicate);
}
else
{
combinedPredicate = combinedPredicate.And(andPredicate);
}
return combinedPredicate;
}
public static void AddToPredicateTypeBasedOnIfAndOrOr<T>(ref Expression<Func<T, bool>> andPredicate,
ref Expression<Func<T, bool>> orPredicate, Expression<Func<T, bool>> newExpression, bool isAnd)
{
if (isAnd)
{
andPredicate = andPredicate ?? BaseAnd<T>();
andPredicate = andPredicate.And(newExpression);
}
else
{
orPredicate = orPredicate ?? BaseOr<T>();
orPredicate = orPredicate.Or(newExpression);
}
}
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}