更新实体错误:在之前的操作完成之前,第二个操作在此上下文上开始

时间:2019-10-09 01:04:24

标签: c# entity-framework entity-framework-core

更新实体时,我在控制器中收到错误

  

在先前的操作完成之前,第二个操作在此上下文上开始。不保证任何实例成员都是线程安全的。

代码:

public class MyController: Controller
{
   private readonly DbContext _db = new DbContext();

方法是

[HttpPatch]
[Route("MyRoute")]
public async Task<ActionResult> UpdateMyCase([Required][FromBody]MyProject body)
{
    using(var dbContextTransaction = _db.Database.BeginTransaction())
    {
        _db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        var p = (from a in _db.MyProject
                 where a.Id == body.Id
                 select a).FirstOrDefault();
        p.Name = "new Name";
        p.Score = "new score";

        // ....
        var m = _db.MyProjectLink.Where(x => x.Id == p.Id);

        for(var key in m)
        {
            if(m.Any(x => x.Id != "something"))
            {
                var link = new MapProjectLink();
                link.MapId = "some id dynamic generated";
                link.Id = body.Id;
                link.Tool = key.tool;
                _db.MapProjectLink.Add(link);
            }
        }

        await _db.SaveChangesAsync();
        return OK(p);
    }
}

为了解释代码,基本上我有三个表。 _db.MyProject,_ db.MyMap_db.MapProjectLink。前两个表是多对多的。第三张表将它们链接在一起。我想将更新后的值保存到两个表:_db.MyProject_db.MapProjectLink

顺便说一下,我现在不使用依赖注入。我猜可能是for循环引起了问题。

错误是

  

在保存上下文类型“ MapProjectLink”的更改时,数据库中发生了异常。 System.InvalidOperationException:在上一个操作完成之前,在此上下文上启动了第二个操作。不保证任何实例成员都是线程安全的。

3 个答案:

答案 0 :(得分:1)

事实证明,我必须将与_db关联的所有内容放入Task.Run中。然后Wait。这意味着等待任务完成,然后继续下一个流程。

答案 1 :(得分:0)

DbContext不是线程安全的。您应该创建一个新的上下文(而不是对每个数据库操作重新使用相同的_db实例。即使对于单线程进程,这也是最佳实践。

旁注-这就是为什么当您等待每个任务都能正常运行时的原因-因为您不再从多个线程访问上下文。

答案 2 :(得分:-1)

我认为您缺少在最后提交事务的功能。...SaveChangesAsync()之后的dbContextTransaction.Commit()应该可以解决问题。