メッセージ:
"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);
私は何を間違えていますか?
問題は次のとおりです。
userLangs.ForEach(async
ForEach
は非同期デリゲートを理解しないため、これはasync void
メソッドを作成しています。したがって、ForEach
の本体は同時に実行され、Entity Frameworkは同時非同期アクセスをサポートしません。
ForEach
をforeach
に変更すると、うまくいくはずです。
foreach (var l in userLangs)
{
var userLanguage = new UserLang();
userLanguage.UserId = userId;
userLanguage.LanguageId = await ...
}
詳細については、私の 非同期ベストプラクティスの記事 の「avoid async void」ガイダンスを参照してください。