zeroframework/Services/DeviceCenter/ZeroFramework.DeviceCenter.Infrastructure/EntityFrameworks/CustomSaveChangesInterceptor.cs
2023-12-05 17:22:48 +08:00

69 lines
3.0 KiB
C#

using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using ZeroFramework.DeviceCenter.Domain.Aggregates.TenantAggregate;
using ZeroFramework.DeviceCenter.Domain.Entities;
namespace ZeroFramework.DeviceCenter.Infrastructure.EntityFrameworks
{
public class CustomSaveChangesInterceptor(IMediator mediator) : SaveChangesInterceptor
{
private readonly IMediator _mediator = mediator;
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
if (eventData.Context is not null)
{
MultiTenancyTracking(eventData.Context);
SoftDeleteTracking(eventData.Context);
DispatchDomainEventsAsync(eventData.Context).Wait();
}
return base.SavingChanges(eventData, result);
}
public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
{
if (eventData.Context is not null)
{
MultiTenancyTracking(eventData.Context);
SoftDeleteTracking(eventData.Context);
await DispatchDomainEventsAsync(eventData.Context, cancellationToken);
}
return await base.SavingChangesAsync(eventData, result, cancellationToken);
}
private static void SoftDeleteTracking(DbContext dbContext)
{
var deletedEntries = dbContext.ChangeTracker.Entries().Where(entry => entry.State == EntityState.Deleted && entry.Entity is ISoftDelete);
deletedEntries?.ToList().ForEach(entityEntry =>
{
entityEntry.Reload();
entityEntry.State = EntityState.Modified;
((ISoftDelete)entityEntry.Entity).IsDeleted = true;
});
}
private static void MultiTenancyTracking(DbContext dbContext)
{
var tenantedEntries = dbContext.ChangeTracker.Entries<IMultiTenant>().Where(entry => entry.State == EntityState.Added || entry.State == EntityState.Modified);
var currentTenant = dbContext.GetService<ICurrentTenant>();
tenantedEntries?.ToList().ForEach(entityEntry =>
{
entityEntry.Entity.TenantId ??= currentTenant.Id;
});
}
private async Task DispatchDomainEventsAsync(DbContext dbContext, CancellationToken cancellationToken = default)
{
var domainEntities = dbContext.ChangeTracker.Entries<IDomainEvents>().Select(e => e.Entity);
var domainEvents = domainEntities.SelectMany(x => x.DomainEvents).ToList();
domainEntities.ToList().ForEach(entity => entity.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
{
await _mediator.Publish(domainEvent, cancellationToken);
}
}
}
}