I have an API controller action that performs about 10 separate linq queries which are used to form a summary object that I need to send back to the client. These linq queries are all performed on the same data. Is there a way that I can use async/await in this scenario so that one linq statement doesn't have to block the others from running? If so, what is the most efficient way to write that async/await code?
To summarize my question:
[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; }
}
How would I use async/await to allow uniqueProductCost, totalProductInventoryValue, and cheapestProduct to execute without waiting for one to finish?
Since you're working on IEnumerable<T>
and not IQueriable<T>
, you can't use async-await
.
Unless you use Task.Run
. But like using async-await
with trully asynchronous APIs (like I/O) in ASP.NET you sacrifice performance for availability, using Task.Run
will sacrifice availability for performance.
If you use Select(x => x.ProductId).Distinct()
. Count()
, you'll allocate a lot less and use a lot less CPU than using Select(x => x.ProductId).Distinct().ToList().Count
.
The same goes for using inventory.OrderBy(x => x.unitPrice).First().ProductId
instead of inventory.OrderBy(x => x.unitPrice).Select(x => x.ProductId).First()
.
Do I have a use case for async/await in this scenario?
If you are sure you want to run these database requests concurrently.
Note that many database clients are limited to one query per connection - in EF terms, this means you'd need a separate db context for each query. This additional complexity (and overhead) may or may not be worth it; you'd have to determine that yourself.
If so, rather than create a bunch of independent tasks and then stuff them all into a Task.WhenAll(), is there a more efficient way to write this so that I can easily add more linq queries later on? (nothing too crazy, just clean and maintainable).
Task.WhenAll
is going to be the cleanest approach. You can pass a List<Task>
to Task.WhenAll
if that's cleaner for you.
Also, as noted in the comments, you'd want to use IQueryable<T>
and not IEnumerable<T>
. It is the communication with the database that must be asynchronous, and that comes at the end of the LINQ expression.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.