简体   繁体   中英

Async/Await Multiple Linq Statements

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:

  1. Do I have a use case for async/await in this scenario?
  2. 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).
[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM