可枚举相交和任何表达式不会编译为 SQL

Enumerable Intersect and Any Expressions do not compile to SQL

我正在尝试为 IQueryable 创建一个扩展方法,它获取一个函数 returning a IEnumerable<Int32>> 作为输入参数,应该对照另一个常量数字列表检查它。如果两个列表中至少包含一个相同的条目,则它应该 return 为真,类似于 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:值不能为空。 bei System.Linq.Expressions.Expression.Lambda(表达式主体、字符串名称、布尔尾调用、IEnumerable`1 参数)

Intersect 查询可能有什么问题?

长话短说:我没有找到让 Intersect() 正常工作的任何解决方案。相反,我更改了我的 Linq 表达式以摆脱相交。我会 post 我的用例的解决方案,也许对以后的人有用。

想法是使用

Where(ListA.Any(x => ListB.Contains(x))
// instead of 
// Where(ListA.Intersect(ListB).Any()

这里是:

public static IQueryable<T> AuthorizedRecords<T>(this IQueryable<T> query, Expression<Func<T, IQueryable<int>>> employeeIds)
{
  var ids = new List<int> { 1, 2, 3 }); // <- changed later

  var methodAny = typeof(Queryable)
        .GetMethods()
        .First(m => m.Name == "Any" && m.GetParameters().Length == 2)
        .MakeGenericMethod(typeof(int));

  Expression<Func<int, bool>> contains = x => ids.Contains(x);
  
  var lambda = Expression.Lambda<Func<T, bool>>(
    Expression.Call(
      methodAny,
      employeeIds.Body,
      contains
    ), 
    employeeIds.Parameters
  );
  
  return query.Where(lambda);
}