简体   繁体   English

EF Core 异步 select InvalidOperationException

[英]EF Core async select InvalidOperationException

The following code以下代码

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()
});

sometimes returns this error:有时会返回此错误:

System.InvalidOperationException: A second operation started on this context before a previous operation completed. System.InvalidOperationException:在前一个操作完成之前在此上下文上启动了第二个操作。

However, this code does not.但是,此代码没有。 To my understanding, it's doing the same thing so I don't understand why it's failing.据我了解,它正在做同样的事情,所以我不明白它为什么会失败。

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

var users = new List<MerchantUser>();
            
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
});
var userTasks = merchant.Users.Select(async u => { … }).ToList();
var users = await Task.WhenAll(userTasks);

This will asynchronously start all those Select tasks at the same time and then wait for them to complete.这将同时异步启动所有这些Select任务,然后等待它们完成。 So this will run multiple things in parallel.所以这将并行运行多个事情。 Since you are querying the user manager inside, this will not work since the underlying connection does not support parallel queries.由于您正在查询内部的用户管理器,因此这将不起作用,因为底层连接不支持并行查询。

In contrast, your foreach loop will only run one query at a time, awaiting the GetRolesAsync before the next iteration begins.相反,您的foreach循环一次只运行一个查询,在下一次迭代开始之前等待GetRolesAsync So instead of working in parallel, the roles will be read sequentially for all users.因此,不是并行工作,而是为所有用户按顺序读取角色。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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