Correct usage of Async/Await for Multiple Tasks To Db
.net, .net-4.5, async-await, c#, task-parallel-library
Solution
What is the correct approach for this scenario when it comes to connecting to a Db and saving entities.
Generally speaking, you should:
- Batch your saves, if possible. In other words, call a single method to update multiple records simultaneously. E.g., EF has `SaveChangesAsync`.
- Use the natural async APIs for your database instead of `Task.Run` (or - even worse - the task constructor). E.g., EF has `SaveChangesAsync`.
Problem
I have a simple scenario but I would like to know if my approach is correct, is it better advised to chose a single task to save my failed orders or can i kick off and fire off multiple tasks and wait for them all to complete. What is the correct approach for this scenario when it comes to connecting to a Db and saving entities. I already have a single task based version of the below that saves one entity into the db. ``` public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress) { var toSave = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList(); var tasks = new Task[toSave.Count()]; for (var i = 0; i < tasks.Length; i++) { var i1 = i; tasks[i] = new Task(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow), TaskCreationOptions.PreferFairness); var message = string.Format("- Order: {0} has been resaved.\n", toSave.ElementAt(i1).Order.FriendlyId); if (progress != null) progress.Report(message); } await Task.WhenAll(tasks); } ``` At the moment, I have tested the above and believe that tasks have not started as the progress bar keeps looping around. My assumption is that Task.WhenAll should start my tasks for me - thats what I think? or should be using this in the loop: ``` tasks[i] = Task.Run(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow)); ``` I think I am close, just want someone to tell me if I a doing this correctly or not. Feedback incorporated version: ``` public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress) { var saveList = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList(); var saveTask = Task.Run(() => { foreach (var ot in saveList) { SaveToDbBatch(oService, oiService, ot); var message = string.Format("- Order: {0} has been resaved.\n", ot.Order.FriendlyId); if (progress != null) progress.Report(message); } }); await saveTask; await Cache.UoW.SaveAsync(); } ```