我有一个API控制器操作,执行大约10个单独的linq查询,这些查询用于形成我需要发送回客户端的摘要对象。这些linq查询都是在相同的数据上执行的。有没有一种方法可以在这种情况下使用async / await,这样一个linq语句就不必阻止其他人运行?如果是这样,编写async / await代码的最有效方法是什么?
总结一下我的问题:
[HttpGet]
public IActionResult GetInventoryDetails(string id)
{
var inventory = _storeInventoryRepo.FindByCondition(s => s.Id = id)
var uniqueProductCount = inventory.Select(x => x.ProductId).Distinct().ToList().Count
var totalProductInventoryValue = inventory.Sum(x =>x.UnitPrice & x.TotalUnits)
var cheapestProduct = inventory.OrderBy(x => x.unitPrice).Select(x => x.ProductId).First();
var inventorydetails = new InventoryDetails
{
UniqueProductCount = uniqueProductCount,
TotalProductInventoryValue = totalProductInventoryValue,
CheapestProduct = cheapestProduct
}
Return Ok(inventoryDetails)
}
public class ProductInventory
{
public string Id { get; set; }
public string ProductId { get; set; }
public int UnitPrice { get; set; }
public double TotalUnits { get; set; }
}
我如何使用async / await来允许执行uniqueProductCost,totalProductInventoryValue和cheapestProduct而无需等待一个完成?
由于你正在使用IEnumerable<T>
而不是IQueriable<T>
,你不能使用async-await
。
除非你使用Task.Run
。但是就像在ASP.NET中使用带有trully异步API(如I / O)的async-await
一样,牺牲性能可用性,使用Task.Run
会牺牲性能的可用性。
如果你使用Select(x => x.ProductId).Distinct()
.Count()
,你将分配更多的东西并使用比使用Select(x => x.ProductId).Distinct().ToList().Count
少得多的CPU。
使用inventory.OrderBy(x => x.unitPrice).First().ProductId
而不是inventory.OrderBy(x => x.unitPrice).Select(x => x.ProductId).First()
也是如此。
在这种情况下,我是否有async / await的用例?
如果您确定要同时运行这些数据库请求。
请注意,许多数据库客户端限制为每个连接一个查询 - 在EF术语中,这意味着您需要为每个查询单独的数据库上下文。这种额外的复杂性(和开销)可能是也可能不值得;你必须自己确定。
如果是这样,而不是创建一堆独立的任务,然后将它们全部填入Task.WhenAll(),是否有更有效的方法来编写它,以便我以后可以轻松添加更多的linq查询? (没什么太疯狂,只是干净和可维护)。
Task.WhenAll
将是最干净的方法。你可以将List<Task>
传递给Task.WhenAll
,如果这对你更清洁的话。
此外,如评论中所述,您想要使用IQueryable<T>
而不是IEnumerable<T>
。它与数据库的通信必须是异步的,并且在LINQ表达式的末尾。