在上一个异步操作完成之前,在此上下文上启动了第二个操作
本文关键字:上下文 启动 操作 第二个 异步操作 上一个 | 更新日期: 2023-09-27 18:16:00
消息:
"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
这是在创建一个async void
方法,因为ForEach
不理解异步委托。所以ForEach
的主体将同时运行,实体框架不支持并发异步访问。
把ForEach
改成foreach
,你应该很好:
foreach (var l in userLangs)
{
var userLanguage = new UserLang();
userLanguage.UserId = userId;
userLanguage.LanguageId = await ...
}
有关更多信息,请参阅我的异步最佳实践文章中的"避免异步无效"指南。
对于那些能够使用.NET 6的人来说,现在有了Parallel.ForEachAsync()
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.foreachasync?view=net-6.0https://www.hanselman.com/blog/parallelforeachasync-in-net-6