From 7efeb4957b2283ca303f36ad7a9d6b4922805ea3 Mon Sep 17 00:00:00 2001 From: Catherine Renelle <32781029+catrenelle@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:00:47 -0500 Subject: [PATCH] Fix concurrency exception when editing loan details RemoveRange + collection replacement caused EF Core to attempt a double-delete on amortization entries. Use Clear() on the tracked collection instead, letting EF handle orphan deletion in a single pass. Co-Authored-By: Claude Opus 4.6 --- src/Purrse.Api/Services/LoanService.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Purrse.Api/Services/LoanService.cs b/src/Purrse.Api/Services/LoanService.cs index 1330055..de6c998 100644 --- a/src/Purrse.Api/Services/LoanService.cs +++ b/src/Purrse.Api/Services/LoanService.cs @@ -70,7 +70,7 @@ public class LoanService : ILoanService var l = account.LoanDetail ?? throw new KeyNotFoundException("No loan detail found"); - _db.AmortizationEntries.RemoveRange(l.AmortizationEntries); + l.AmortizationEntries.Clear(); l.OriginalBalance = request.OriginalBalance; l.InterestRate = request.InterestRate; @@ -82,7 +82,8 @@ public class LoanService : ILoanService l.ExtraPayment = request.ExtraPayment; var entries = GenerateAmortizationSchedule(l); - l.AmortizationEntries = entries; + foreach (var entry in entries) + l.AmortizationEntries.Add(entry); await _db.SaveChangesAsync(); var schedule = entries.Select(e => new AmortizationEntryResponse(e.PaymentNumber, e.PaymentDate, e.PaymentAmount, e.PrincipalAmount, e.InterestAmount, e.EscrowAmount, e.RemainingBalance)).ToList();