C# 保持';LINQ表达式节点类型';调用&x27;在LINQ to实体';例外情况

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

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

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); } }