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

Ale*_*dre 2 linq-to-entities

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);
}
Run Code Online (Sandbox Code Playgroud)

代码_categoryRepository.GetSingle(lambda)抛出异常:"LINQ to Entities中不支持LINQ表达式节点类型'Invoke'"

有没有简单的方法来避免这种异常?我不想使用其他工具,如LinqKit或PredicateBuilder.

Lor*_*nVS 6

这进入了Linq2Entities背后的一些管道以及Linq2Objects和Linq2AnythingElse之间的区别......

您显然对表达式树有很好的理解,并且您以编程方式生成它们.Linq2Entities获取该表达式树并尝试将其转换为SQL查询以在数据库服务器上运行.但是,它无法将任意C#代码映射到其SQL等效项(例如,toBll调用在SQL中绝对没有意义).

换句话说,你遇到了这个问题,因为Linq2Entities试图将你的toBll调用映射到SQL,并且由于没有这样的等价物而失败了.您正在尝试做的事情中存在一些设计缺陷.我假设您正在尝试在数据库服务器上运行的"where"中表达任意条件.但是,您的任意条件是业务层对象,SQL服务器和实体框架都不了解这些对象.

你真正需要做的是这种设计,就是根据Linq2Entities类型而不是你的BLL类型来表达任意条件.由于Linq2Entities知道这些类型,它将能够将任意表达式转换为SQL(因为它具有Linq2Entities类型与其SQL等价物的映射).

我上面描述的是实际执行此操作的正确方法,或者,您可以枚举查询(将执行),然后针对返回的结果集运行条件.从那时起,你在Linq2Objects(它只是针对内存中对象运行的标准.NET代码)中运行,你的函数将运行没有问题.但是,这意味着你的"where"子句将在内存中运行,而不是在数据库服务器上运行,所以我真的不推荐这个

编辑:OP请求代码...

为了使其正常工作,您需要更改GetSingle方法以获取作用于EntityFramework类型的表达式条件,而不是BLL类型.然后,您可以从表达式树中删除转换器子句,并且应该启动并运行:

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));
}
Run Code Online (Sandbox Code Playgroud)

这种方法的问题在于您的表达式必须与EntityFramework类型有关,这可能违反了隐藏数据抽象层细节的愿望.那时候,它真的很难运气,EntityFramework + BLL +动态查询生成=很难做对