添加两个表达式以在Entity Framework Core 3中创建谓词不起作用 [英] Add two expressions to create a predicate in Entity Framework Core 3 does not work

查看:101
本文介绍了添加两个表达式以在Entity Framework Core 3中创建谓词不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在.NET Core应用程序中使用带有Entity Framework Core 3的C#构建 And谓词方法。

I am trying to build an "And" predicate method using C# with Entity Framework Core 3 in a .NET Core application.

该函数向每个函数添加两个表达式其他并将其传递给IQueryable代码:

The function adds two expressions to each other and passes it to an IQueryable code:

public Expression<Func<T, bool>> AndExpression<T>
                    (Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
      var andExpression = Expression.AndAlso(
           left.Body, Expression.Invoke(right,
           left.Parameters.Single()));

      return Expression.Lambda<Func<T, bool>>(andExpression, left.Parameters);
}

该函数的调用

Expression<Func<Entity, bool>> left = t => t.Id == "id1";
Expression<Func<Entity, bool>> right = t => t.Id == "id2";
var exp = AndExpression(left, right);
this.dbContext.Set<Entity>().source.Where(exp).ToList();

我的代码在EF Core 2版本中运行良好,但是在我将版本更新为版本3之后以下异常

My code works fine in version EF Core 2, but after I updated the version to version 3 it throws the following exception


LINQ表达式'Where(
来源:DbSet,
谓词:(s)=> (t => t.Id == id1)&&调用(t => t.Id == id2)
)'无法翻译。以一种可以翻译的形式重写查询,或者通过
插入对AsEnumerable(),AsAsyncEnumerable(),
ToList()或ToListAsync()的调用来显式切换到客户端评估。 / p>

The LINQ expression 'Where( source: DbSet, predicate: (s) => (t => t.Id == "id1") && Invoke(t => t.Id == "id2") )' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().

由于内存问题,我无法将查询转换为Enumerable。
我理解这个问题,但是我不知道是否有办法避免它。

I cannot translate the query to Enumerable due to memory issues. I understand the problem but I don't know if there is a way to avoid it.

如果有人给我小费,我将不胜感激。非常感谢!

If anyone has a tip for me, I would appreciate that. Thanks a lot!

推荐答案

您需要打开lambda的主体,而不要使用 Expression。调用。您还必须至少重写一个lambda,以便它们都使用相同的参数。

You need to unwrap the bodies of your lambdas, rather than using Expression.Invoke. You'll also have to rewrite at least one of the lambdas, so they both use the same parameters.

我们将使用 ExpressionVisitor 用左边的相应参数替换right的参数。然后,我们将使用左侧的主体和从右侧重写的主体构造 AndExpression ,最后创建一个新的lambda。

We'll use an ExpressionVisitor to replace right's parameter with the corresponding parameter from left. Then we'll construct the AndExpression using left's body and the rewritten body from right, and finally create a new lambda.

public class ParameterReplaceVisitor : ExpressionVisitor
{
    public ParameterExpression Target { get; set; }
    public ParameterExpression Replacement { get; set; }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == Target ? Replacement : base.VisitParameter(node);
    }
}

public static Expression<Func<T, bool>> AndExpression<T>(
    Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
    var visitor = new ParameterReplaceVisitor()
    {
        Target = right.Parameters[0],
        Replacement = left.Parameters[0],
    };

    var rewrittenRight = visitor.Visit(right.Body);
    var andExpression = Expression.AndAlso(left.Body, rewrittenRight);
    return Expression.Lambda<Func<T, bool>>(andExpression, left.Parameters);
}

这会产生带有以下DebugView的lambda:

This results in a lambda with the following DebugView:

.Lambda #Lambda1<System.Func`2[System.String,System.Boolean]>(Entity $t) {
    $t.Id == "id1" && $t.Id == "id2"
}

而您的代码将生成lambda使用以下DebugView:

Whereas your code results in a lambda with the following DebugView:

.Lambda #Lambda1<System.Func`2[System.String,System.Boolean]>(System.String $t) {
    $t == "id1" && .Invoke (.Lambda #Lambda2<System.Func`2[System.String,System.Boolean]>)($t)
}

.Lambda #Lambda2<System.Func`2[System.String,System.Boolean]>(System.String $t) {
    $t == "id2"
}

看看您是如何从lambda(EF无法处理的事情)中调用lambda的,而我的只有一个lambda。

See how yours is calling a lambda from within a lambda (something that EF can't handle), whereas mine just has a single lambda.

这篇关于添加两个表达式以在Entity Framework Core 3中创建谓词不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆