The LINQ expression node type 'Invoke' is not supported in LINQ to Entities
1 2 3 4 5 6 7 8 9 10 11 | public CategoryViewModel GetSingle( Expression<Func<CategoryViewModel, bool>> where) { Expression<Func<DAL.EntityModels.Category, CategoryViewModel>> converter = c => ToBll(c); var param = Expression.Parameter(typeof(DAL.EntityModels.Category),"category"); var body = Expression.Invoke(where, Expression.Invoke(converter, param)); var lambda = Expression.Lambda<Func<DAL.EntityModels.Category, bool>>(body, param); return (CategoryViewModel )_categoryRepository.GetSingle(lambda); } |
代码_categoryRepository.GetSingle(lambda)引发异常:" LINQ to Entities不支持LINQ表达式节点类型'Invoke'"
有没有简单的方法可以避免这种异常? 我不想使用其他工具,例如LinqKit或PredicateBuilder。
这涉及到Linq2Entities背后的一些问题以及Linq2Objects和Linq2AnythingElse之间的区别...
您显然对表达式树有很好的理解,并且可以通过编程方式生成它们。 Linq2Entities使用该表达式树,并尝试将其转换为SQL查询以在数据库服务器上运行。但是,它不能将任意C#代码映射到与其等效的SQL上(例如,toBll调用在SQL中绝对没有意义)。
换句话说,您遇到了这个问题,因为Linq2Entities试图将您的toBll调用映射到SQL中,并且由于没有这样的等效项而失败了。您尝试执行的操作中存在一些设计缺陷。我假设您正在尝试获取以" where"表示的任意条件,以便在数据库服务器上运行。但是,您的任意条件取决于业务层对象,并且SQL Server和实体框架都不了解这些对象。
对于这种设计,您真正需要做的是用Linq2Entities类型而不是BLL类型表示任意条件。由于Linq2Entities知道这些类型,因此它将能够将任意表达式转换为SQL(因为它具有Linq2Entities类型到它们的SQL等效项的映射)。
我上面描述的确实是执行此操作的正确方法,或者,您可以枚举查询(将执行该查询),然后对返回的结果集运行条件。由于此时您正在Linq2Objects中运行(这只是针对内存中对象运行的标准.NET代码),因此您的函数将毫无问题地运行。但是,这意味着您的" where"子句将在内存中运行,而不是在数据库服务器上运行,因此我真的不建议这样做
编辑:OP请求的代码...
为了使其正常工作,您需要更改GetSingle方法以采用对EntityFramework类型而不对BLL类型起作用的表达式条件。然后,您可以从表达式树中删除converter子句,并且应该已启动并正在运行:
1 2 3 4 5 6 7 8 9 | public CategoryViewModel GetSingle( Expression<Func<DAL.EntityModels.Category, bool>> where) { var param = Expression.Parameter(typeof(DAL.EntityModels.Category),"category"); var body = Expression.Invoke(where, param); var lambda = Expression.Lambda<Func<DAL.EntityModels.Category, bool>>(body, param); return ToBLL((DAL.EntityModels.Category)_categoryRepository.GetSingle(lambda)); } |
这种方法的问题在于,您的表达式必须以EntityFramework类型表示,这可能违反了您隐藏数据抽象层细节的愿望。那时,运气非常糟糕,EntityFramework + BLL +动态查询生成=难以正确完成