2016-11-16 18 views
1

我是新來的實體框架,我很困惑正確的方式來處置我的DbContext當一個方法調用另一個。這些都是獨立調用的,這就是爲什麼DeleteSheet是分開的。但是,刪除父項(鏈)時,DeleteChain調用DeleteSheet刪除子項。正確的方式來處置DbContext時,一個方法調用另一個,都使用DbContext

我嘗試各種方法來處理,但是當我運行DeleteChain我得到:

The operation cannot be completed because the DbContext has been disposed. 

db.Chains.Remove(chain); 

我猜這是因爲我在DeleteSheet取出時處置它兒童。

這裏是我的方法:

public class ControllerHelper 
{ 
    private UranusContext db = new UranusContext(); 

    public void DeleteChain(int? chainId) 
    { 
     var chain = db.Chains.Include(c => c.Sheets) 
      .SingleOrDefault(c => c.ChainId == chainId); 

     // Removes sheets (children) 
     foreach (var sheet in chain.Sheets.ToList()) 
     { 
      DeleteSheet(sheet.SheetId); 
     } 

     db.Chains.Remove(chain); 
     db.SaveChanges(); 
     db.Dispose(); 
    } 

    public void DeleteSheet(int? sheetId) 
    { 
     var sheet = db.Sheets.Include(s => s.FileDetails) 
      .Include(s => s.SheetsCounties) 
      .SingleOrDefault(s => s.SheetId == sheetId); 

     foreach (var fileDetails in sheet.FileDetails.ToList()) 
     { 
      db.FileDetails.Remove(fileDetails); 
     } 

     foreach (var sheetsCounties in sheet.SheetsCounties.ToList()) 
     { 
      db.SheetsCounties.Remove(sheetsCounties); 
     } 

     db.Sheets.Remove(sheet); 
     db.SaveChanges(); 

     db.Dispose(); 
    } 
} 

如何正確在這種情況下處置的DbContext的?我很困惑,因爲如果我只在DeleteChain中處理,然後在DeleteChain之外調用DeleteSheet,它將不會處理。

編輯:嘗試#2。我將每個包裝在一個使用中,並分別處理它們。但是,當我刪除DeleteSheet中的子項時,DeleteChain並未意識到我做到了這一點並拋出:The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.db.SaveChanges(),DeleteChain

嘗試#2。

public void DeleteChain(int? chainId) 
{ 
    using (UranusContext db = new UranusContext()) 
    { 
     var chain = db.Chains.Include(c => c.Sheets) 
      .SingleOrDefault(c => c.ChainId == chainId); 

     // Removes sheets (children) 
     foreach (var sheet in chain.Sheets.ToList()) 
     { 
      DeleteSheet(sheet.SheetId); 
      //db.Sheets.Remove(sheet); 
     } 

     db.Chains.Remove(chain); 
     db.SaveChanges(); 
    } 
} 

public void DeleteSheet(int? sheetId) 
{ 
    using (UranusContext db = new UranusContext()) 
    { 
     var sheet = db.Sheets.Include(s => s.FileDetails) 
      .Include(s => s.SheetsCounties) 
      .SingleOrDefault(s => s.SheetId == sheetId); 

     foreach (var fileDetails in sheet.FileDetails.ToList()) 
     { 
      db.FileDetails.Remove(fileDetails); 
     } 

     foreach (var sheetsCounties in sheet.SheetsCounties.ToList()) 
     { 
      db.SheetsCounties.Remove(sheetsCounties); 
     } 

     db.Sheets.Remove(sheet); 
     db.SaveChanges(); 
    } 
} 

回答

1

你可能想移動表刪除邏輯在不同的方法,並從兩個DeleteChain和DeleteSheet調用它,就像這樣:

public class ControllerHelper 
{ 
    public void DeleteChain(int? chainId) { 
     using (var db = new UranusContext()) { 
      var chain = db.Chains.Include(c => c.Sheets) 
       .SingleOrDefault(c => c.ChainId == chainId); 

      // Removes sheets (children) 
      foreach (var sheet in chain.Sheets.ToList()) { 
       DeleteSheet(db, sheet); 
      } 

      db.Chains.Remove(chain); 
      db.SaveChanges(); 
     } 
    } 

    public void DeleteSheet(int? sheetId) { 
     using (var db = new UranusContext()) { 
      var sheet = db.Sheets.Include(s => s.FileDetails) 
       .Include(s => s.SheetsCounties) 
       .SingleOrDefault(s => s.SheetId == sheetId); 

      DeleteSheet(db, sheet); 
      db.SaveChanges(); 
     } 
    } 

    private void DeleteSheet(UranusContext db, Sheet sheet) { 
     foreach (var fileDetails in sheet.FileDetails.ToList()) { 
      db.FileDetails.Remove(fileDetails); 
     } 

     foreach (var sheetsCounties in sheet.SheetsCounties.ToList()) { 
      db.SheetsCounties.Remove(sheetsCounties); 
     } 

     db.Sheets.Remove(sheet); 
    } 
} 
+0

這似乎是最可行和有效的。我只有一個問題:當你傳遞UranusContext數據庫時,是不是創建了一個UranusContext的新實例?是處置還是增加了不必要的開銷? – justiceorjustus

+0

不,當您傳遞對上下文的引用時 - 不會創建任何內容(並且根本沒有開銷)。 – Evk

0

的最簡單的方法是將通過的DbContext作爲參數:

public class ControllerHelper 
{ 
    public void DeleteChain(int? chainId, UranusContext db) 
    { 
     var chain = db.Chains.Include(c => c.Sheets) 
      .SingleOrDefault(c => c.ChainId == chainId); 

     // Removes sheets (children) 
     foreach (var sheet in chain.Sheets.ToList()) 
     { 
      DeleteSheet(sheet.SheetId, db); 
     } 

     db.Chains.Remove(chain); 
    } 

    public void DeleteSheet(int? sheetId, UranusContext db) 
    { 
     var sheet = db.Sheets.Include(s => s.FileDetails) 
      .Include(s => s.SheetsCounties) 
      .SingleOrDefault(s => s.SheetId == sheetId); 

     foreach (var fileDetails in sheet.FileDetails.ToList()) 
     { 
      db.FileDetails.Remove(fileDetails); 
     } 

     foreach (var sheetsCounties in sheet.SheetsCounties.ToList()) 
     { 
      db.SheetsCounties.Remove(sheetsCounties); 
     } 

     db.Sheets.Remove(sheet); 
    } 
} 

,然後用它像

public void Foo(int? someChainId, int? someSheetId, bool required = false) 
{ 
    ControllerHelper hlp = new ControllerHelper(); 
    using (UranusContext db = new UranusContext()) 
    { 
     hlp.DeleteChain(someChainId); 

     if(_required) 
      hlp.DeleteSheet(int? someSheetId); 

     db.SaveChanges(); 
    } 
} 
0

嘗試使用圖案和傳遞上下文作爲參數來DeleteSheet方法如此:

public class ControllerHelper 
{ 
    public void DeleteChain(int? chainId) 
    { 
    using (UranusContext db = new UranusContext()) 
    { 
      var chain = db.Chains.Include(c => c.Sheets) 
       .SingleOrDefault(c => c.ChainId == chainId); 

      // Removes sheets (children) 
      foreach (var sheet in chain.Sheets.ToList()) 
      { 
       DeleteSheet(sheet.SheetId, db); 
      } 

      db.Chains.Remove(chain); 
      db.SaveChanges(); 
    } 
    } 

    public void DeleteSheet(int? sheetId, UranusContext db) 
    { 
     var sheet = db.Sheets.Include(s => s.FileDetails) 
      .Include(s => s.SheetsCounties) 
      .SingleOrDefault(s => s.SheetId == sheetId); 

     foreach (var fileDetails in sheet.FileDetails.ToList()) 
     { 
      db.FileDetails.Remove(fileDetails); 
     } 

     foreach (var sheetsCounties in sheet.SheetsCounties.ToList()) 
     { 
      db.SheetsCounties.Remove(sheetsCounties); 
     } 

     db.Sheets.Remove(sheet); 
     db.SaveChanges(); 
    } 
} 

通過這種方式,您可以確保僅在所有刪除操作完成後才處理上下文。我一直試圖避免同時使用多個上下文,以前我一直在嚴重燒傷它!

+0

我遇到的問題是,我在我的控制器類,這使我有打電話DeleteSheet本身在那裏創建另一個DbContext來調用它。我仍然不喜歡它,但也許我很挑剔。 – justiceorjustus

+0

解決了這個問題,但調用了'SaveChanges()''chain.Sheets''次,如果SaveChanges()'有任何重載,這可能是一個問題。 – jpk

+0

編寫一個DeleteSheet的覆蓋,它帶有Id和上下文,並保留其他東西。 – DrMistry

0

在你的設計中ControllerHelperUranusContext的組成。這意味着您設計只要ControllerHelper存在,UranusContext存在,並且您希望UranusCibtextControllerHelper不存在時立即停止存在。

通過使它成爲一個組合,您可以向您的課程的用戶保證,只要您的課程存在,您的所有功能都能正常工作。因此,在您的用戶通知您他們不再需要您的功能之前,您不應該在您的任何功能中使用Dispose()UranusContext。這可以通過使您的ControllerHelper IDisposable

如果任何類實現IDisposable,此類的設計者鼓勵用戶在他不再需要對象的功能後儘快致電Dispose()

在你的情況下,代碼是:

public class ControllerHelper : IDisposable() 
{ 
    private UranusContext db = new UranusContext(); 

    public void Dispose() 
    { 
     if (this.db != null) 
     { 
      this.db.Dispose(); 
      this.db = null; 
     } 
     GC.SuppressFinalize(this); 
    } 

    public void DeleteChain(int? chainId) 
    { 
     // Do what you need to do, but don't Dispose() 
     // nor use using, we want db to be functional 
    } 
    public void DeleteSheet(int? sheetId) 
    { 
     // Do what you need to do, but don't Dispose() 
     // nor use using, we want db to be functional 
    } 
} 

用法是:

using (var controllerHelper = new ControllerHelper()) 
{ 
    // call functions from controllerhelper 
} 
// the controllerHelper is not needed anymore, Dispose() is called automatically 
// and thus db is Disposed 
+0

我更喜歡這個。 「使用(UranusContext db = new UranusContext())''確保正確處置?我遵循@Evk的解決方案,但我仍然懷疑將UranusContext作爲參數傳遞,並且沒有正確處理。 – justiceorjustus

相關問題