MVC Core 2.0 EF Core SqlException:不允许新事务,因为会话中还有其他线程在运行

时间:2017-12-06 19:28:16

标签: c# asp.net-mvc entity-framework asp.net-core-2.0 ef-core-2.0

这个问题有很多线索,但大多数线程似乎出现在有人试图循环并保存在IQueryable而不是IList上的情况下,这不是我正在做的事情。

我遇到了在我的控制器和我的存储库之间传递上下文的问题。我在我的应用程序的其他地方遇到了这个问题,但下面是一个简单的说明和重新创建的方法。

首先,我将Startup.cs中的DbContext设置为服务。

services.AddDbContext<ApplicationDbContext>(options =>
      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

然后,我有一个控制器,它被注入。当我直接从控制器使用上下文时,前两个保存工作正常,但是当我从repo中使用它时,它会在标题中出现异常。请注意,在我尝试将其保存在我的仓库中之前,如果我在控制器中保存记录,则只会出错。

 private ApplicationDbContext _context;
 private UserManager<ApplicationUser> _userManager;

 private ApplicationUser _user
    {
        get
        {
            return _userManager.GetUserAsync(User).Result;
        }
    }

 public InitiativesController(ApplicationDbContext context, UserManager<ApplicationUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    // GET: Initiatives
    public IActionResult Index()
    {

        Initiative i2 = new Initiative();
        i2.Id = 2;
        i2.InitiativeName = "testname";
        _context.Update(i2);
        _context.SaveChanges(); // Works fine

        var i4 = _context.Initiatives.SingleOrDefault(init => init.Id == 2);
        i4.InitiativeName = "blep";
        _context.Update(i4);
        _context.SaveChanges(); // Works fine


        InitiativeRepository initiativeRepository = new InitiativeRepository(_context, _user);

        var i= initiativeRepository.Get(2);
        i.InitiativeName = "blah";
        initiativeRepository.Update(i); //Throws exception

        var initiatives = initiativeRepository.GetAll();
        return View(initiatives);
    }

这是存储库类:

public class InitiativeRepository
{
    private ApplicationDbContext _context;
    private ApplicationUser _user;

    public InitiativeRepository(ApplicationDbContext context, ApplicationUser user)
    {
        _context = context;
        _user = user;
    }

    public Initiative Get(int id, bool eagerLoad = false)
    {
        if (!eagerLoad)
        {
            return _context.Initiatives.SingleOrDefault(i => i.Id == id);
        }
        else
        {
            return _context.Initiatives.Include(i => i.Tasks).ThenInclude(t => t.ActionItems).
                SingleOrDefault(i => i.Id == id);
        }
    }

    public List<Initiative> GetAll()
    {
        return _context.Initiatives.ToList();
    }

    public Initiative Update(Initiative Entity)
    {
        _context.Update(Entity);
        _context.SaveChanges(); // This line causes the exception.
        return Entity;
    }

}

这应该是任何数据库写入的入口点,但是,我正在使用ASP.NET身份并在此会话中自动登录,所以我不确定它是否也会影响这一点。

1 个答案:

答案 0 :(得分:0)

我始终不相信依赖注入这样的事情会发生。虽然令人讨厌,但您可以更好地服务于您的仓库中的所有内容,或者通过以下方式关闭和处理您的上下文:

using(var context = new context("yourContext"))
{
   //dowork
   context.SaveChanges();  
}

即使它不应该发生什么,这只是猜测。是否注入在传入时会捕获上下文的错误状态。您可以在repo的构造函数中执行依赖注入,然后直接在repo中执行CRUD操作。

private InitiativeRepository _initiativeRepository;


public InitiativesController(ApplicationDbContext context, UserManager<ApplicationUser> userManager)
{
    _context = context;
    _userManager = userManager;
    _initiativeRepository = new InitiativeRepository(_context, _user);

}

我使用带有控制器的.NET Core 2 Web Api执行上述模式。我知道任何时候我保留了一个上下文而没有关闭它然后将该上下文与另一个使用它的状态混合在一起,我遇到了麻烦。我也没有在内容中使用依赖注入,因此有趣的是新的.NET Core将它们作为默认设置。在大型数据库和多用户应用程序完成大量工作之前,它可能会很有用。