2014-12-19 33 views
0

所以我偶然發現了一件奇怪的事情。 我有一個測試,改變workingsiteuntil日至昨天,像這樣:Db上下文 - 多種用法

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); 
     } 

在這個測試中我斷言失敗,until沒有改變對象workingSiteFromDb,但在我的代碼做變化它並保存對數據庫的更改。 note:我的數據庫沒有更新!我在數據庫中檢查了日期,並且正確地修改了日期。

現在我不知道發生了什麼,所以我在第一個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僅設置UntilDateDateTime.Now.AddDays(-1)

+0

您可以顯示EndWorkingSitePeriod()的代碼嗎? – 2014-12-19 08:53:57

+0

已更新問題以顯示此信息 – Tikkes 2014-12-19 09:01:09

回答

2

首先,你在某處獲得workingSiteToEnd並將其添加到背景下,您的樣品的第一行創建。然後,您將保存更改(workingSiteToEnd現在位於上下文中的數據庫中)。

然後,您正在創建EndWorkingSitePeriod方法的第二個上下文。使用該上下文,您將獲得新的workingSiteFromDb實例(它與上面的workingSiteToEnd無關)。您正在修改它並保存更改。

現在,您正試圖測試您所做的更改,但原始workingSiteToEnd仍然存在於上下文中。這意味着,當您嘗試從數據庫中再次加載它時,在實現過程中,上下文將查找具有相同密鑰的實體,並在其本地緩存中找到該實體,並返回原來的實體,即original,不變workingSiteToEnd(你可以比較引用,他們將是平等的)。

當你第一次SaveChanges後立即關閉using塊,然後創建新的,你要創建背景下,這將載入新實例workingSiteFromDb,測試將通過。

+0

我的一位同事也告訴我,只有通過'Linq'使用'Find'並且'First'會再次訪問數據庫**,而使用'Find '如果可能的話好多了。謝謝你的回答。這解釋了這個問題非常好。 – Tikkes 2014-12-19 09:17:36

0

請勿嵌套使用相同的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); 
    } 
} 
+0

因爲我正在經歷一次測試,所以我不打算在這上面傳遞我的applicationDbContext。 – Tikkes 2014-12-19 09:16:17