【发布时间】:2021-02-17 09:39:07
【问题描述】:
我正在尝试为 IQueryable 创建一个扩展方法,该方法获取一个返回 IEnumerable<Int32>> 作为输入参数的函数,应对照另一个常数列表检查该函数。如果两个列表中至少包含一个相同的条目,则它应该返回 true,例如 listA.Intersect(listB).Any()。此表达式还必须很好地编译为 SQL(最新的 EF 核心)(Intersect() 和 Any() 自己应该这样做)。所以这是我想出的(还):
public static IQueryable<T> AuthorizedRecords<T>(this IQueryable<T> query, Expression<Func<T, IEnumerable<Int32>>> employeeIds)
{
var ids = (new List<int> { 1, 2, 3 }).AsEnumerable(); // <- replaced later
var methodAny = typeof(Enumerable)
.GetMethods()
.Where(m => m.Name == "Any" && m.GetParameters().Length == 1)
.First()
.MakeGenericMethod(typeof(int));
var methodIntersect = typeof(Enumerable)
.GetMethods()
.Where(m => m.Name == "Intersect" && m.GetParameters().Length == 2)
.First()
.MakeGenericMethod(typeof(int));
var lambdaParam = employeeIds.Parameters.Single();
var lambda = Expression.Lambda(
Expression.Call(
methodAny,
Expression.Call(
methodIntersect,
Expression.Constant(ids),
employeeIds.Body
)
),
lambdaParam
);
var predicate = (Expression<Func<T, bool>>)lambda;
return query.Where(predicate);
}
此代码可以编译,但我得到一个运行时错误,即 LINQ 表达式 <...> 无法转换为 sql。表达有什么问题?
更新
表达式似乎没问题,但 Intersect() 方法由于某种原因失败了。我将代码简化为重现错误的最小 Linq 查询:
dbContext.Meetings
.Where(e => e.AccessList
.Select(x => x.Id)
.Intersect((new List<int>() { 90, 91, 92 })
.Any()
);
现在我得到一个 System.ArgumentNullException: Value cannot be null。 bei System.Linq.Expressions.Expression.Lambda(表达式主体,字符串名称,布尔tailCall,IEnumerable`1个参数)
Intersect 查询可能有什么问题?
【问题讨论】:
-
您正在使用
Enumerable的Any和Intersect方法,而不是Queryable。Enumerable是内存中的 LINQ。 -
将其更改为 Queryable 并从文档中注意到
Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>)的第二个参数必须是IEnumerable<TSource>,因此我将它们交换为Expression.call(...)。当使用dbContext.Meetings.AuthorizedRecords(e => e.AccessList.Select(x => x.Id).AsQueryable()调用它时,我得到一个运行时错误 Value cannot be null。 (参数“参数”)。当使用 const List 而不是e => e.AccessList.Select(x时,一切正常。有什么建议吗? -
你能用最新的代码/错误更新你的问题吗?
-
请看下面我的回答,我已经在那里发布了我的工作代码示例
标签: c# lambda linq-to-sql expression