2016-11-01 11 views
6

wiadomość:Druga operacja rozpoczęła się na tym kontekście przed zakończona poprzednia operacja asynchroniczna

"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." 

kod:

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

co starałem:

I Nie jestem pewien, co robię źle, próbowałem różnych rzeczy E:

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. innych prób i błędów ułożenia, że nie zapomnij teraz

Co robię źle?

Odpowiedz

18

Oto problem:

userLangs.ForEach(async 

To jest stworzenie metody async void, ponieważ ForEach nie rozumie asynchronicznych delegatów. Ciało jednostki ForEach zostanie uruchomione jednocześnie, a Entity Framework nie obsługuje równoczesnego dostępu asynchronicznego.

Zmiana ForEach do foreach, a powinno być dobre: ​​

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

Aby uzyskać więcej informacji, zobacz „uniknąć asynchronicznej pustkę” wytyczne w moim Async Best Practices article.

Powiązane problemy