gpt4 book ai didi

c# - 将 LinqKit PredicateBuilder 用于相关模型 (EF Core)

转载 作者:太空狗 更新时间:2023-10-29 20:19:24 25 4
gpt4 key购买 nike

我想使用 LinqKit 的 PredicateBuilder 并将谓词传递给相关模型的 .Any 方法。

所以我想建立一个谓词:

var castCondition = PredicateBuilder.New<CastInfo>(true);

if (movies != null && movies.Length > 0)
{
castCondition = castCondition.And(c => movies.Contains(c.MovieId));
}
if (roleType > 0)
{
castCondition = castCondition.And(c => c.RoleId == roleType);
}

然后使用它来过滤与谓词中的模型有关系的模型:

IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition));
return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();

但这会导致 System.NotSupportedException: 无法解析表达式 'n.CastInfo.Any(Convert(__castCondition_0, Func``2))': 给定的参数与预期的参数不匹配:对象类型“System.Linq.Expressions.UnaryExpression”无法转换为类型“System.Linq.Expressions.LambdaExpression”。

我看到了similar question并在那里回答建议使用 .Compile。或者 one more question构建一个额外的谓词。

所以我尝试使用额外的谓词

var tp = PredicateBuilder.New<Name>(true);
tp = tp.And(n => n.CastInfo.Any(castCondition.Compile()));
IQueryable<Name> result = _context.Name.AsExpandable().Where(tp);

或者直接编译

IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castCondition.Compile()));

但是我有一个关于编译的错误:System.NotSupportedException: Could not parse expression 'n.CastInfo.Any(__Compile_0)'

那么是否可以将 PredicateBuilder 的结果转换为传递给Any

注意:我能够构建所需的行为组合表达式,但我不喜欢这样,因为我需要额外的变量。

System.Linq.Expressions.Expression<Func<CastInfo,bool>> castExpression = (c => true);
if (movies != null && movies.Length > 0)
{
castExpression = (c => movies.Contains(c.MovieId));
}
if (roleType > 0)
{
var existingExpression = castExpression;
castExpression = c => existingExpression.Invoke(c) && c.RoleId == roleType;
}
IQueryable<Name> result = _context.Name.AsExpandable().Where(n => n.CastInfo.Any(castExpression.Compile()));
return await result.OrderBy(n => n.Name1).Take(25).ToListAsync();

所以我想我只是错过了一些关于构建器的东西。

关于版本的更新:我使用 dotnet core 2.0 和 LinqKit.Microsoft.EntityFrameworkCore 1.1.10

最佳答案

查看代码,我们会假设 castCondition 的类型变量是 Expression<Func<CastInfo, bool>> (就像在 PredicateBuilder 的早期版本中一样)。

但如果是这样的话,那么n.CastInfo.Any(castCondition)甚至不应该编译(假设 CastInfo 是一个集合导航属性,所以编译器将命中 Enumerable.Any 期望 Func<CastInfo, bool> ,而不是 Expression<Func<CastInfo, bool>> )。那么这是怎么回事?

在我看来,这是 C# 隐式运算符滥用的一个很好的例子。 PredicateBuilder.New<T>方法实际上返回一个名为 ExpressionStarter<T> 的类,它有很多模拟 Expression 的方法,但更重要的是,隐式转换为 Expression<Func<T, bool>>Func<CastInfo, bool> .后者允许该类用于顶级 Enumerable/Queryable方法作为相应 lambda 函数/表达式的替换。但是,它也可以防止在表达式树中使用时出现编译时错误,就像您的情况一样 - 编译器会发出类似 n.CastInfo.Any((Func<CastInfo, bool>)castCondition) 的内容。这当然会在运行时导致异常。

LinqKit 的整体思路 AsExpandable方法是允许通过自定义“调用”表达式 Invoke扩展方法,然后在表达式树中“扩展”。所以回到开头,如果变量类型是Expression<Func<CastInfo, bool>> ,预期用途是:

_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.Invoke(c)));

但由于前面解释的原因,现在它无法编译。所以你必须先把它转换成Expression<Func<T, bool>查询的外部:

Expression<Func<CastInfo, bool>> castPredicate = castCondition;

然后使用

_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castPredicate.Invoke(c)));

_context.Name.AsExpandable().Where(n => n.CastInfo.Any(castPredicate.Compile()));

为了让编译器推断表达式类型,我将创建一个自定义扩展方法,如下所示:

using System;
using System.Linq.Expressions;

namespace LinqKit
{
public static class Extensions
{
public static Expression<Func<T, bool>> ToExpression<T>(this ExpressionStarter<T> expr) => expr;
}
}

然后简单地使用

var castPredicate = castCondition.ToExpression();

它仍然必须在查询的之外完成,即以下工作:

_context.Name.AsExpandable().Where(n => n.CastInfo.Any(c => castCondition.ToExpression().Invoke(c)));

关于c# - 将 LinqKit PredicateBuilder 用于相关模型 (EF Core),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46706255/

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