分配谓词变量而不是 lambda 表达式
Posted
技术标签:
【中文标题】分配谓词变量而不是 lambda 表达式【英文标题】:Assigning a predicate variable instead of a lambda expression 【发布时间】:2021-12-20 05:05:34 【问题描述】:以下教科书 Join 查询运行良好:
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 ;
list
是IQueryable: 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
的不同重载。你应该在那里传递Expression<Func<Family, bool>>
,而不是Func<Family, bool>
。
我该怎么做?我将query
更改为Expression<Predicate<Family>> query = f => !f.isDeleted;
,但无法将其放入.Where(query)
。
请再次阅读我的评论。我没说Expression<Predicate<Family>>
。
谢谢。现在可以了。我理解错了Predicate<T>
和Func<T, bool>
一样。
它在概念上是相同的,但它们仍然是不同类型的委托,即使它们具有相同的签名。而 Where 则特别期望 Func。
【参考方案1】:
您正在调用Where
的两个非常不同的重载。在第一个代码 sn-p 中,您正在调用:
Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>
)
此重载将您的 lambda 表达式转换为 SQL 查询并在数据库上运行。
在第二个代码 sn-p 中,您正在调用
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)
...
【讨论】:
以上是关于分配谓词变量而不是 lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章