LINQ to Entities不支持LINQ表达式节点类型’Invoke’

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 +动态查询生成=难以正确完成