c# - .NET Core Entity Framework - 异步写入数据库
问题描述
我有个问题。我有 ASP .NET Core REST API 应用程序,并且在一种方法中,我试图将更多更改异步写入数据库。每次将不同数量的对象写入数据库时,每次出现三种不同错误之一。任何建议可以是错的?
这是我的代码:
启动.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connection_string), ServiceLifetime.Transient);
services.AddScoped<IHelper, Helper>();
...
}
助手.cs
private MyDbContext _dbContext;
public Helper(IOptions<HelperSettings> settings, ILogger<Helper> logger, MyDbContext dbContext)
{
...
_dbContext = dbContext;
...
}
public void Save(object entity)
{
...
_dbContext.Add(entity);
}
这是引发异常的控制器和方法。
public class MyController : ControllerBase
{
private readonly Helper _db;
public MyController(IHelper helper)
{
_db = helper;
}
...
[HttpPost]
[Route("something")]
[Produces("application/json")]
public async Task<ActionResult<Guid>> CreateSomethingAsync([FromBody] DataRequest data)
{
...
if (data.Answers != null)
{
List<Task> saveTasks = new List<Task>();
foreach (AnswerData ans in data.Answers)
{
Answer answer = ans.ConvertToAnswer(); //just create new Answer instance and filll it with data from AnswerData
saveTasks.Add(Task.Run(() => _db.Save(answer)));
}
await Task.WhenAll(saveTasks);
await _db.DbContext.SaveChangesAsync();
}
return Ok(...);
}
}
我CreateSomethingAsync()
在另一个应用程序中循环调用。它抛出以下三个异常之一:
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
或者
System.InvalidOperationException: 'Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.'
或者
System.InvalidOperationException: Cannot start tracking InternalEntityEntry for entity type 'Answer' because another InternalEntityEntry is already tracking the same entity
_dbContext.Add(entity);
在我的线上Helper.cs
。
我知道问题出在并行性上,但我不知道如何解决。有任何想法吗?
解决方案
DbContext 不是线程安全的(这就是您得到的异常告诉您的),并且调用DbContext.Set<T>.Add()
不会花费大量时间。通过并行化,Add()
您不会将多个实体异步添加到数据库中 - 您只是在调用时将实体标记为待添加SaveChanges()
。
因此,虽然我确定您有理由并行化您的_db.Save(answer)
调用,但它可能没有任何性能改进,因此您可以完全删除它,将工作序列化。
如果您在那里所做的工作确实受益于并行化,只需将调用DbContext.Set<T>.Add()
移出那里 - 它不是线程安全的。
推荐阅读
- java - 创建一个 Gradle 设置以在 Jitpack 上使用源代码发布依赖项?(等级 5.6.2)
- javascript - 通过 javascript 将 CSS 样式添加到特定类
- scala - 通过 Scala 中的反射确定构造函数参数计数和类型
- html - 改变
- 以 4 行间隔垂直到水平列出
- pointers - 为什么在某些情况下零大小的类型会导致实际分配?
- database - 如何加快具有许多布尔字段的 mongo db 查询?
- c# - 创建一个指向任意数据的位域类——这安全吗?
- html - 如何从 JSON 中添加文本“
“?
- javascript - 如何找到确定特定像素颜色的 CSS/HTML 规则
- javascript - 通过 config.json 文件注册时,导入语句会破坏 typeorm 实体