LINQ to Entities的例外不支持继续获取’LINQ表达式节点类型’调用’

我正在使用C#(包括Linq)来开发Web应用程序。 我编写了一个generics方法来扩展任何实体的Get方法。 但是当我得到运行时exception时,执行代码时,“LINQ to Entities”不支持LINQ表达式节点类型“Invoke”。 以下是代码:

using System.Linq; using System.Linq.Expressions; using LinqKit; public static class ServiceExtension { public static IEnumerable GetActive(this ICrudService crudService, Expression<Func> where) where T : class, IDeletable { return crudService.Get(where.And(w => !w.IsDeleted)); } } 

有人可以告诉我我做错了什么吗?

您正在使用LinqKit,它只适用于已AsExpandable()可查询AsExpandable() 。 这将包装底层查询提供程序,并将对InvokeAnd在内部使用)的所有调用转换为查询提供程序将理解的内容。

另一种方法是不使用LinqKit,并使用以下版本的PredicateBuilder,它可以和/或谓词表达式,而不依赖于Invoke的使用:

 public static class PredicateBuilder { public static Expression> True() { return f => true; } public static Expression> False() { return f => false; } public static Expression> Or( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters); } public static Expression> And( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (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); } 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); } } 

Servy的答案很棒,对我来说非常有用。 我已经采取了它并稍微扩展/改变它,并将它添加到这个以回报一点点。

首先,我将True和False属性重命名为BaseAnd(而不是True)和BaseOr(而不是false)。 基于我如何使用它们以获得我想要的结果,主要是这对我来说更容易理解。

另外,我添加了两个新的generics函数:AddToPredicateTypeBasedOnIfAndOrOr,它接受两个ref谓词,一个用于os,一个用于ors,并将在其中一个上添加一个表达式,具体取决于它是否应该是和否。 这只是为了减少代码重复,因为我的代码在应用程序运行之前不知道它应该是哪种类型。

CombineOrPreicatesWithAndPredicates接受初始谓词表达式,谓词表达式和谓词表达式,并以sql逻辑方式(和列表)和(或列表)组合它们。 这也是为了减少代码重复。

希望这有助于那里的人。

 public static class PredicateBuilder { public static Expression> BaseAnd() { return f => true; } public static Expression> BaseOr() { return f => false; } public static Expression> Or( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters); } public static Expression> And( this Expression> expr1, Expression> expr2) { var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]); return Expression.Lambda> (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> CombineOrPreicatesWithAndPredicates(this Expression> combinedPredicate, Expression> andPredicate, Expression> orPredicate) { combinedPredicate = combinedPredicate ?? BaseAnd(); 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(ref Expression> andPredicate, ref Expression> orPredicate, Expression> newExpression, bool isAnd) { if (isAnd) { andPredicate = andPredicate ?? BaseAnd(); andPredicate = andPredicate.And(newExpression); } else { orPredicate = orPredicate ?? BaseOr(); 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); } } 

我相信问题出在你的方法中。 您可以使用静态Expression方法自己创建表达式

 public static IEnumerable GetActive(this ICrudService crudService, Expression> 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>(andExpression, parameter); return crudService.Get(lambda); }