简体   繁体   English

异步方法上的C#Entity Framework错误

[英]C# Entity Framework error on async methods

I have already seen this, but I am experiencing another problem. 我已经看过了,但我遇到了另一个问题。

I have this service class for managing ASP.NET identity roles: 我有这个用于管理ASP.NET身份角色的服务类:

public class RoleService : IRoleService
{
    private readonly RoleManager<ApplicationRole> _roleManager;

    public RoleService(RoleManager<ApplicationRole> roleManager)
    {
        this._roleManager = roleManager;
    }

    public async Task<IdentityResult> CreateAsync(ApplicationRole role)
    {
        return await this._roleManager.CreateAsync(role);
    }
}

As suggested by this question , I use the CreateAsync method like this to avoid using LINQ foreach : 正如这个问题所建议的那样,我使用这样的CreateAsync方法来避免使用LINQ foreach

private async Task PopulateRoles()
{
     var roles = new[] { "A", "B", "C", "D" };

     // Used LINQ foreach previously but I coded this way instead to follow the related questions's answer
     var tasks = roles.Select(role =>
                           this._roleService.CreateAsync(new ApplicationRole(role)))
                      .ToList();

     await Task.WhenAll(tasks);
}

However, this results in an error when await this.PopulateRoles() is executed. 但是,这会在await this.PopulateRoles()执行时导致错误。

Entity Framework: There is already an open DataReader associated with this Command which must be closed first. 实体框架:已经有一个与此命令关联的开放DataReader,必须先关闭它。

Searching for this error only leads me to a suggestion of adding a ToList() in my Select LINQ. 搜索此错误只会导致我在Select LINQ中添加ToList()的建议。 How can I fix it? 我该如何解决?

The problem lays with the RoleManager<T> which internally is given a single DbContext as we can see here : 问题在于RoleManager<T> ,在内部给出了一个DbContext ,我们可以在这里看到:

public class RoleStore<TRole, TContext, TKey> : 
        IQueryableRoleStore<TRole>, 
        IRoleClaimStore<TRole>
        where TRole : IdentityRole<TKey>
        where TKey : IEquatable<TKey>
        where TContext : DbContext
{
    public RoleStore(TContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        Context = context;
    }
}

DbContext itself can't handle concurrent calls. DbContext本身无法处理并发调用。 The alternative would be to execute each of the calls inside a foreach and await each one: 另一种方法是执行foreach每个调用并await每个调用:

private async Task PopulateRoles()
{
     var roles = new[] { "A", "B", "C", "D" };

     foreach (var role in roles)
     {
         await _roleService.CreateAsync(new ApplicationRole(role));
     }
}

This way, though you don't have the benefit of applying all roles concurrently, you do still take advantage of the async nature of the IO call, instead of a blocking synchronous call. 这样,虽然您没有同时应用所有角色的好处,但仍然可以利用IO调用的异步特性,而不是阻塞同步调用。

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

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