Skip to content

Commit fdf7dc5

Browse files
committed
VCST-3962: Delete orphaned entities (#466)
1 parent 8a94ee8 commit fdf7dc5

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

src/VirtoCommerce.OrdersModule.Data/Repositories/OrderRepository.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Threading.Tasks;
55
using Microsoft.EntityFrameworkCore;
6+
using Microsoft.EntityFrameworkCore.ChangeTracking;
67
using VirtoCommerce.OrdersModule.Core.Model;
78
using VirtoCommerce.OrdersModule.Data.Model;
89
using VirtoCommerce.Platform.Core.Common;
@@ -17,6 +18,9 @@ public class OrderRepository : DbContextRepositoryBase<OrderDbContext>, IOrderRe
1718
public OrderRepository(OrderDbContext dbContext, IUnitOfWork unitOfWork = null)
1819
: base(dbContext, unitOfWork)
1920
{
21+
// Resolves Breaking changes in EF Core 7.0 (EF7) when EF Core will not automatically delete orphans because all FKs are nullable.
22+
// https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/breaking-changes?tabs=v7#orphaned-dependents-of-optional-relationships-are-not-automatically-deleted
23+
dbContext.SavingChanges += OnSavingChanges;
2024
}
2125

2226
public IQueryable<CustomerOrderEntity> CustomerOrders => DbContext.Set<CustomerOrderEntity>();
@@ -247,5 +251,72 @@ public virtual async Task RemoveOrdersByIdsAsync(IList<string> ids)
247251
}
248252
}
249253
#pragma warning restore S109
254+
255+
protected override void Dispose(bool disposing)
256+
{
257+
if (disposing && DbContext != null)
258+
{
259+
DbContext.SavingChanges -= OnSavingChanges;
260+
}
261+
base.Dispose(disposing);
262+
}
263+
264+
protected virtual bool IsOrphanedEntity(EntityEntry entry)
265+
{
266+
switch (entry.Entity)
267+
{
268+
case CaptureEntity capture
269+
when capture.PaymentId == null:
270+
case RefundEntity refund
271+
when refund.PaymentId == null:
272+
case PaymentInEntity payment
273+
when payment.CustomerOrderId == null
274+
&& payment.ShipmentId == null:
275+
case AddressEntity a
276+
when a.CustomerOrderId == null
277+
&& a.ShipmentId == null
278+
&& a.PaymentInId == null:
279+
case DiscountEntity d
280+
when d.CustomerOrderId == null
281+
&& d.ShipmentId == null
282+
&& d.LineItemId == null
283+
&& d.PaymentInId == null:
284+
case TaxDetailEntity t
285+
when t.CustomerOrderId == null
286+
&& t.ShipmentId == null
287+
&& t.LineItemId == null
288+
&& t.PaymentInId == null:
289+
case FeeDetailEntity f
290+
when f.CustomerOrderId == null
291+
&& f.ShipmentId == null
292+
&& f.LineItemId == null
293+
&& f.PaymentInId == null:
294+
case OrderDynamicPropertyObjectValueEntity v
295+
when v.CustomerOrderId == null
296+
&& v.PaymentInId == null
297+
&& v.ShipmentId == null
298+
&& v.RefundId == null
299+
&& v.LineItemId == null
300+
&& v.CaptureId == null:
301+
return true;
302+
}
303+
304+
return false;
305+
}
306+
307+
private void OnSavingChanges(object sender, SavingChangesEventArgs args)
308+
{
309+
var ctx = (DbContext)sender;
310+
var entries = ctx.ChangeTracker.Entries();
311+
312+
foreach (var entry in entries)
313+
{
314+
if (entry.State == EntityState.Modified &&
315+
IsOrphanedEntity(entry))
316+
{
317+
entry.State = EntityState.Deleted;
318+
}
319+
}
320+
}
250321
}
251322
}

0 commit comments

Comments
 (0)