如何使用 LINQ 异步调用带有子记录的数据库?
Posted
技术标签:
【中文标题】如何使用 LINQ 异步调用带有子记录的数据库?【英文标题】:How to asynchronously call a database with subrecords using LINQ? 【发布时间】:2013-10-12 23:29:34 【问题描述】:我正在使用 EF6 并希望使以下查询完全异步:
await MyDataContext.ADbSet.
First(a => a.Something == "Something").
ASubCollection.
Select(x => new x.SubCollectionId ).
ToListAsync();
这行不通,我相信是因为First()
返回了实际实体,并且对ASubCollection
的访问权是ICollection
,而不是IQueryable
。
我可以使用以下代码解决此问题:
await MyDataContext.ADbSet.
Where(a => a.Something == "Something").
SelectMany(a => a.ASubCollection).
Select(x => new x.SubCollectionId ).
ToListAsync();
但是,这似乎很“hacky”,因为我使用的是Where(...)
,而我应该使用First()
,因为我在编译时知道只有一个元素可以满足查询。有更好的方法吗?
【问题讨论】:
@VladimirFrolov 在什么时候?请详细说明。.ADbSet.Where(a => a.Something == "Something").Take(1)
【参考方案1】:
对First()
的调用实际上是枚举底层序列并返回一个实体而不是Task
。因此First()
不能与await
关键字一起使用。
您的第二个解决方案在这种情况下是完全有效的(根本不是“hacky”),因为不需要对生成的数据库查询添加限制,因为Where(...)
-call 将在这种特殊情况 - 查询中有或没有限制。
如果Where
-调用可能返回多个元素,或者您只是想确保只考虑第一个元素,插入对Take(1)
的调用将带来序列的第一个元素,但是仍然是IQueryable
:
await MyDataContext.ADbSet
.Where(a => a.Something == "Something")
.Take(1)
.SelectMany(a => a.ASubCollection)
.Select(x => new x.SubCollectionId )
.ToListAsync();
【讨论】:
嗯,这就是 Joel Spolsky 所说的“泄露抽象” :) 感谢您提供信息! @DarkWanderer 看来你是对的! :) 对于那些像我一样可能想知道“泄漏抽象”是什么的人,这里是 Joel 博客的链接:The Law of Leaky Abstractions以上是关于如何使用 LINQ 异步调用带有子记录的数据库?的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to Object - 如何为子组实现 WHERE 子句“如果至少有一个元素是”
给元素添加子节点,元素子节点数改变,反过来影响上方调用其值的异步任务回调函数(如click。load,定时器等