首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >继续获取“LINQ表达式节点类型”“Invoke”在LINQ to Entities中不受支持“”异常

继续获取“LINQ表达式节点类型”“Invoke”在LINQ to Entities中不受支持“”异常
EN

Stack Overflow用户
提问于 2014-03-14 21:52:11
回答 3查看 9.4K关注 0票数 9

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

代码语言:javascript
复制
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));
    }
}

有人能告诉我我哪里做错了吗?

EN

回答 3

Stack Overflow用户

发布于 2014-03-14 22:01:50

您使用的是LinqKit,它只对调用了AsExpandable()的可查询项起作用。这将包装底层查询提供程序,并将对Invoke ( And在内部使用)的所有调用转换为查询提供程序可以理解的内容。

另一种选择是干脆不使用LinqKit,而是使用以下版本的PredicateBuilder,它可以和/或谓词表达式,而不依赖于Invoke的使用

代码语言:javascript
复制
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);
    }
}

相反,它依赖以下方法将一个表达式的所有实例替换为另一个表达式:

代码语言:javascript
复制
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);
    }
}
票数 22
EN

Stack Overflow用户

发布于 2015-11-13 02:37:50

Servy的答案很棒,对我非常有用。我已经对其进行了扩展/更改,并将其添加到本文中,以获得更多回报。

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

此外,我添加了两个新的泛型函数: AddToPredicateTypeBasedOnIfAndOrOr,它接受两个引用谓词,一个用于and,另一个用于or,并将根据是否应为and向其中一个添加表达式。这只是为了减少代码重复,因为在应用程序运行之前,我的代码不知道它应该是哪种类型。

CombineOrPreicatesWithAndPredicates采用初始谓词表达式、and谓词表达式和or谓词表达式,并以逻辑方式将它们组合在一起,(and list) and (or list)。这也是为了减少代码重复。

希望这能对外面的人有所帮助。

代码语言:javascript
复制
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);
    }
}
票数 4
EN

Stack Overflow用户

发布于 2014-03-14 22:08:12

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

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22406952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档