当一个方法调用另一个方法并且都使用DbContext时,处理DbContext的正确方法
本文关键字:方法 DbContext 处理 一个 另一个 调用 | 更新日期: 2023-09-27 18:18:17
我是实体框架的新手,当一个方法调用另一个方法时,我对处理DbContext的正确方法感到困惑。这两个都是独立调用的,这就是为什么deleetesheet是独立的。然而,DeleteChain调用deleetesheet来删除父链(Chain)时的子链。
我尝试在每个方法中处理,但当我运行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之外调用deleetesheet,它不会处置。
编辑:尝试#2。我把每个包裹在一个使用和处理他们单独。然而,当我删除DeleteSheet
中的子代时,DeleteChain
没有意识到我这样做了,并且在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()
。
尝试# 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();
}
}
您可能希望将表删除逻辑移动到单独的方法中,并从DeleteChain和deleetesheet中调用它,如下所示:
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);
}
}
最简单的方法是将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();
}
}
尝试使用模式并将上下文作为参数传递给deleetesheet方法,如下:
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();
}
}
这样,您就可以确保只有在所有的删除操作完成后才会处理上下文。我总是尽量避免在同一时间使用多个上下文,我以前就被这个问题严重烧伤过!
在您的设计中,ControllerHelper
是UranusContext
的组合。这意味着您设计了只要ControllerHelper
存在,UranusContext
就存在,并且您希望UranusCibtext
在ControllerHelper
不再存在时立即停止存在。
通过使它成为一个组合,你向你的类的用户承诺,只要你的类存在,你的所有函数都可以工作。因此,在用户通知您他们不再需要您的功能之前,您不应该在任何函数中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