如何使用 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 子句“如果至少有一个元素是”

如何编写异步LINQ查询?

给元素添加子节点,元素子节点数改变,反过来影响上方调用其值的异步任务回调函数(如click。load,定时器等

给元素添加子节点,元素子节点数改变,反过来影响上方调用其值的异步任务回调函数(如click。load,定时器等

如何在 LINQ SQL C# 中返回动态周数?

实战 EF(LINQ) 如何以子查询的形式来 Join