gpt4 book ai didi

c# - 添加两个表达式以在 Entity Framework Core 3 中创建谓词不起作用

转载 作者:行者123 更新时间:2023-11-30 21:26:56 25 4
gpt4 key购买 nike

我正在尝试在 .NET Core 应用程序中使用 C# 和 Entity Framework Core 3 构建一个“And”谓词方法。

该函数将两个表达式相加并将其传递给 IQueryable 代码:

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 后它抛出以下异常

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。我明白这个问题,但我不知道是否有办法避免它。

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

最佳答案

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

我们将使用 ExpressionVisitor 将右侧的参数替换为左侧的相应参数。然后我们将使用左边的主体和从右边重写的主体构造 AndExpression,最后创建一个新的 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:

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

而您的代码会生成具有以下 DebugView 的 lambda:

.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 内部调用 lambda(这是 EF 无法处理的),而我的只有一个 lambda。

关于c# - 添加两个表达式以在 Entity Framework Core 3 中创建谓词不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58630723/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com