Следующий код

var merchant = await _dbContext.Merchants
   .Include(m => m.Users)
   .SingleAsync(m => m.MerchantId == id);
 
var userTasks = merchant.Users.Select(async u =>
{
   var roles = await _userManager.GetRolesAsync(u);

   return new MerchantUser
   {
      UserName = u.UserName,
      Role = string.Join(",", roles)
   };
}).ToList();

var users = await Task.WhenAll(userTasks);
            
return View(new MerchantViewModel
{
   MerchantId = merchant.MerchantId,
   MerchantName = merchant.Name,
   MerchantUsers = users.ToList()
});

иногда возвращается эта ошибка:

System.InvalidOperationException: Вторая операция началась в этом контексте до завершения предыдущей операции.

Однако этот код не работает. Насколько я понимаю, он делает то же самое, поэтому я не понимаю, почему он не работает.

var merchant = await _dbContext.Merchants
    .Include(m => m.Users)
    .SingleAsync(m => m.MerchantId == id);

var users = new List();
            
foreach (var user in merchant.Users)
{
    var roles = await _userManager.GetRolesAsync(user);
                
    users.Add(new MerchantUser
    {
        UserName = user.UserName,
        Role = string.Join(",", roles)
    });
}
            
return View(new MerchantViewModel
{
    MerchantId = merchant.MerchantId,
    MerchantName = merchant.Name,
    MerchantUsers = users
});

Ответы (1)

var userTasks = merchant.Users.Select(async u => { ... }).ToList();
var users = await Task.WhenAll(userTasks);

Это асинхронно запустит все эти задачи Select в одно и то же время, а затем будет ждать их завершения. Таким образом, будет выполняться несколько задач параллельно. Поскольку вы запрашиваете менеджер пользователей внутри, это не сработает, так как базовое соединение не поддерживает параллельные запросы.

В отличие от этого, ваш цикл foreach будет выполнять только один запрос за раз, ожидая GetRolesAsync перед началом следующей итерации. Таким образом, вместо параллельной работы роли будут считываться последовательно для всех пользователей.

2022 WebDevInsider