【问题标题】:A second operation started on this context before a previous asynchronous operation completed在前一个异步操作完成之前在此上下文上启动了第二个操作
【发布时间】:2017-03-14 19:30:24
【问题描述】:

消息:

"System.NotSupportedException was unhandled
Message: An unhandled exception of type 'System.NotSupportedException' occurred in mscorlib.dll
Additional information: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe."

代码:

public async Task<IEnumerable<UserLangDTO>> ImportLang(int userId)
{
    var userLangs = new List<UserLangDTO>();
    using (FirstContext ctx = new FirstContext())
    {
        if (await (ctx.UserLang.AnyAsync(u => u.UserId == userId)) == false)
            //some exception here

        userLangs = await ctx.UserLang.AsNoTracking()
                                .Where(ul => ul.UserId == userId)
                                .Join(ctx.Language,
                                    u => u.LangID,
                                    l => l.LangID,
                                    (u, l) => new { u, l })
                                .Join(ctx.Level,
                                    ul => ul.u.LevelID,
                                    le => le.LevelID,
                                    (ul, le) => new { ul, le })
                                .Select(r => new UserLangDTO
                                {
                                UserId = r.ul.u.UserId,
                                Language = r.ul.l.Language,
                                Level = r.le.Level,
                                }).ToListAsync().ConfigureAwait(false);

    }
    using (SecondContext ctx = new SecondContext())
    {
        if ( await (ctx.UserLangs.AnyAsync(u => u.UserId == userId)) == true && userLangs.Any())
            ctx.UserLangs.RemoveRange(ctx.UserLangs.Where(u => u.UserId == userId));
        if (await hasUserLangs && userLangs.Any())
        {
            userLangs.ForEach(async l =>
            {
                var userLanguage = new UserLang();
                userLanguage.UserId = userId;
                userLanguage.LanguageId = await ctx.Languages.AsNoTracking()
                                                 .Where(la => la.NameEn == l.Language)
                                                 .Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false);
                userLanguage.LevelId = await ctx.Levels.AsNoTracking()
                                                .Where(la => la.NameEn == l.Language)
                                                .Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false);

                ctx.UserLangs.Add(userLanguage);
            });
        }
        await ctx.SaveChangesAsync().ConfigureAwait(false);
    }
    return userLangs;
}

我尝试了什么:

我不确定自己做错了什么,我尝试了不同的方法,例如:

1.

await Task.Run(() => Parallel.ForEach(strings, s =>
{
    DoSomething(s);
})); 

2.

var tasks = userLangs.Select(async l =>
{
    //rest of the code here
}
await Task.WhenAll(tasks); 

3.

var tasks = userLangs.Select(async l =>
{
    //rest of the code here
}
await Task.WhenAll(tasks);

await ctx.SaveChangesAsync().ConfigureAwait(false); 
  1. 其他尝试和错误尝试,我现在不记得了

我做错了什么?

【问题讨论】:

    标签: c# .net asynchronous parallel-processing


    【解决方案1】:

    这是你的问题:

    userLangs.ForEach(async
    

    这是创建一个async void 方法,因为ForEach 不理解异步委托。所以ForEach的body会并发运行,Entity Framework不支持并发异步访问。

    ForEach 更改为foreach,你应该会很好:

    foreach (var l in userLangs)
    {
      var userLanguage = new UserLang();
      userLanguage.UserId = userId;
      userLanguage.LanguageId = await ...
    }
    

    有关详细信息,请参阅我的Async Best Practices article 中的“避免异步无效”指南。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-08
      • 2021-05-04
      • 1970-01-01
      • 2022-01-01
      • 2020-01-22
      • 1970-01-01
      • 2018-11-07
      相关资源
      最近更新 更多