Question:
I am encountering an issue with the rollback behavior in Entity Framework transactions. I have a scenario where I am deleting a parent entity along with its child entities within a transaction. However, if an exception occurs before the transaction is committed, the rollback successfully restores the parent entity, but the child entity records remain deleted.
Here's the simplified code structure:
PaymentController.cs
try
{
uow.BeginTransaction();
var moneyTransaction = uow.MoneyTransactions.GetById(id);
var log = new LogRecord(LogRecordType.Delete)
{
TransId = moneyTransaction.Id,
TransType = moneyTransaction.Type,
Data1 = moneyTransaction.Splits[0].Account.ToString(),
Data2 = moneyTransaction.Splits[1].Account.ToString(),
Notes = moneyTransaction.Notes,
};
uow.LogRecords.Add(log);
uow.MoneyTransactions.Delete(id);
deleted = uow.Save();
}
catch (Exception ex)
{
uow.Rollback();
throw ex;
}
UoW.cs
public bool Save()
{
var saved = _context.SaveChanges();
transaction.Commit();
return saved > 0;
}
public void BeginTransaction()
{
transaction = _context.Database.BeginTransaction();
}
public void Rollback()
{
transaction.Rollback();
}
The issue is that the Splits child entity records are not restored during the rollback, while the parent entity MoneyTransaction is successfully restored when an exception is thrown.
How can I ensure that the child entity records (Splits) are also rolled back when an exception occurs within the transaction scope? Is there a better approach to handle these scenarios effectively?
My try:
Edit:
I have this code in BbContext Class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Transaction>()
.HasMany(t => t.Splits)
.WithRequired(s => s.Transaction)
.HasForeignKey(s => s.Transaction_Id)
.WillCascadeOnDelete(true);
modelBuilder.Entity<Transaction>()
.Property(t => t.RowVersion)
.IsRowVersion();
base.OnModelCreating(modelBuilder);
}
}
I solve this problem by initializing DbContext instance in each form separately, as previously I was initializing it only in Program.cs file and passing it same to all the program, like this:
using (DBContext cxt = new DBContext())
{
Application.Run(new FormLogin(cxt));
}
Now become like this:
Program.cs
Application.Run(new FormLogin());
FormLogin.cs
public FormLogin()
{
cxt = new DBContext();
}