分配谓词变量而不是 lambda 表达式

Assigning a predicate variable instead of a lambda expression

以下教科书连接查询运行良好:

var list = from family in db.Families.Where(f => !f.isDeleted)
  join member in db.Members.Where(m => !m.isDeleted)
  on family.Id equals member.FamilyID
  select new { family = family.LastName, member = member.DisplayName };

listIQueryable: {Microsoft.FrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType0<string, string>>} 我可以调用 list.ToList().

但是,如果我在第一个 Where 中使用谓词,而不是使用 lambda,如下所示:

Predicate<Family> query = f => !f.isDeleted;
var list = from family in db.Families.Where(new Func<Family, bool>(query))
  join member in db.Members.Where(m => !m.isDeleted)
  on family.Id equals member.FamilyID
  select new { family = family.LastName, member = member.DisplayName };

然后 list 变成 [IEnumerable]: {System.Linq.Enumerable.<JoinIterator>d__105<Family, Member, short, <>f__AnonymousType0<string, string>>} 并且结果视图抛出“已经有一个打开的 DataReader 与此连接关联,必须先关闭它。”。

我无法再重现它,但我确定有时结果视图会抛出“数据为空”异常。

我需要将过滤器设置为变量,因为所需的确切过滤器取决于其他一些条件。为什么使用 Predicate 赋值会导致 list 的类型不同,我该如何解决这个错误?

您正在调用 Where 的两个截然不同的重载。在第一个代码片段中,您正在调用:

Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>)

此重载将您的 lambda 表达式转换为 SQL 查询并在数据库上运行它。

在第二个代码片段中,您正在调用

Where<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>)

第二个重载是 LINQ to Objects Where,它根本不知道您的数据库。它适用于所有 IEnumerable<T>s.

您应该创建一个 Expression<Func<Family, bool>> 并将其传入:

Expression<Func<Family, bool>> query = f => !f.isDeleted;
var list = from family in db.Families.Where(query)
    ...