justiceorjustus justiceorjustus - 24 days ago 6
C# Question

Proper way to dispose DbContext when one method calls another and both use DbContext

I'm new to Entity Framework and I'm confused about the proper way to dispose my DbContext when one method is calling another. These both get called independently, which is why DeleteSheet is separate. However, DeleteChain calls DeleteSheet to remove children when the parent (Chain) is deleted.

I try to dispose in each method, but when I run DeleteChain I get:

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


on

db.Chains.Remove(chain);


I'm guessing it's because I disposed of it in DeleteSheet when removing the children.

Here are my methods:

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


How do I properly dispose of DbContext in this case? I'm confused since if I only dispose in DeleteChain and then DeleteSheet is called outside of DeleteChain, it won't dispose.

Edit: Attempt #2. I wrap each in a using and dispose of them individually. However, when I delete the children in
DeleteSheet
,
DeleteChain
doesn't realize I did that and throws:
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.
on
db.SaveChanges()
in
DeleteChain
.

Attempt #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();
}
}

Evk Evk
Answer

You might want to move sheet deletion logic in separate method and call it from both DeleteChain and DeleteSheet, like this:

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