数据库上下文 - 多种用法

本文关键字:用法 上下文 数据库 | 更新日期: 2023-09-27 18:34:44

所以我刚才偶然发现了一件奇怪的事情。我有一个测试,它将workingsiteuntil日期更改为昨天,如下所示:

using (var db = new ApplicationDbContext())
        {
            var empFromDb = db.Employees.Include(x => x.WorkingSites).First(x => x.Id == _employeeId);
            empFromDb.WorkingSites.Add(workingSiteToEnd);
            db.SaveChanges();
        //Act
        ServiceFactory.CreateEmployeeService().EndWorkingSitePeriod(workingSiteToEnd);
        //Assert
            var workingSiteFromDb = db.WorkingSites.First(x => x.Id == workingSiteToEnd.Id);
            Assert.AreEqual(DateTime.Now.AddDays(-1).Date, workingSiteFromDb.WorksUntil.Date);
        }

在此测试中,我的断言失败,并且对象workingSiteFromDbuntil没有更改,但在我的代码中,我确实更改了它并将更改保存到数据库中。注意:我的数据库确实更新了!我在数据库中进行了检查,日期更改正确。

现在我不知道发生了什么,所以我在第一次savechanges后立即停止了using,并在我打电话之前再次打开workingSiteFromDb

如果我这样做,它就会起作用。

请注意,我在 EndWorkingSitePeriod 方法中使用了另一个using

为什么我的数据库确实更新了,但对象仅在我使用第二个using时才更新?

这是EndWorkingSitePeriod方法:

public void EndWorkingSitePeriod(int workingSiteId)
    {
        using (var db = new ApplicationDbContext())
        {
            var workingSiteFromDb = db.WorkingSites.Include(x => x.Employee).First(x => x.Id == workingSiteId);
            workingSiteFromDb.EndPeriod();
            db.SaveChanges();
        }
    }

workingSite.EndPeriod只是将UntilDate设置为DateTime.Now.AddDays(-1)

数据库上下文 - 多种用法

首先

,您在某处获取workingSiteToEnd并将其添加到上下文中,在示例的第一行中创建。然后,您将保存更改(现在workingSiteToEnd保存在数据库上下文中(。

然后,您将EndWorkingSitePeriod方法中创建第二个上下文。使用该上下文,您将获得新的workingSiteFromDb实例(它与上面的workingSiteToEnd无关(。您正在修改它,并保存更改。

现在,您正在尝试测试所做的更改,但原始workingSiteToEnd仍然存在于上下文中。这意味着,当您尝试再次从数据库加载它时,上下文将在具体化过程中查找其本地缓存中具有相同键的实体,将找到它,并将返回现有实体,该实体是原始的,未更改的workingSiteToEnd(您可以比较引用,它们将是相等的(。

当您在第一次SaveChanges块后立即关闭using块,然后创建新块时,您正在创建新的上下文,这将加载workingSiteFromDb的新实例,并且测试将通过。

不要嵌套使用同一 DbContext。相反,如果您需要在调用方法中使用相同的上下文,请使用参数传递它,例如:

using (var db = new ApplicationDbContext())
{
   var empFromDb = db.Employees.Include(x => x.WorkingSites).First(x => x.Id == _employeeId);
   empFromDb.WorkingSites.Add(workingSiteToEnd);
   db.SaveChanges();
   //Act
   ServiceFactory.CreateEmployeeService().EndWorkingSitePeriod(workingSiteToEnd, db);
   //Assert
   var workingSiteFromDb = db.WorkingSites.First(x => x.Id == workingSiteToEnd.Id);
   Assert.AreEqual(DateTime.Now.AddDays(-1).Date, workingSiteFromDb.WorksUntil.Date);
}
private void EndWorkingSitePeriod(int workingSiteId, ApplicationDbContext db)
{
    var workingSiteFromDb = db.WorkingSites.Include(x => x.Employee).First(x => x.Id == workingSiteId);
    workingSiteFromDb.EndPeriod();
    db.SaveChanges();
}
// if you need it public, then use this too
public void EndWorkingSitePeriod(int workingSiteId)
{
    using (var db = new ApplicationDbContext()) 
    {
       EndWorkingSitePeriod(workingSiteId, db);
    }
}