Sto sviluppando un'applicazione web utilizzando ASP.NET Core + Entity Framework Core .
Mi piacerebbe memorizzare più informazioni riguardanti la creazione , modifica e cancellazione .
Le mie entità EF implementano interfacce che portano i seguenti campi:
DateTime CreationTime { get; set; }
long? CreatorUserId { get; set; }
DateTime? ModificationTime { get; set; }
long? ModifierUserId { get; set; }
DateTime? DeletionTime { get; set; }
public long? DeleterUserId { get; set; }
bool IsDeleted { get; set; }
int TenantId { get; set; }
Ho cercato di rendere la mia app impostata automaticamente su tutti i campi.
DateTime
: AppDbContext.cs
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
ChangeTracker.DetectChanges();
ChangeTracker.ProcessModifiedTime();
ChangeTracker.ProcessSoftDelete();
ChangeTracker.ProcessCreationTime();
return (await base.SaveChangesAsync(true, cancellationToken));
}
ChangeTrackerExtensions.cs
public static class ChangeTrackerExtensions
{
public static void ProcessCreationTime(this ChangeTracker changeTracker)
{
foreach (var item in changeTracker.Entries<ICreationTime>().Where(e => e.State == EntityState.Added))
{
item.CurrentValues[AppConsts.CreationTime] = DateTime.Now;
}
}
public static void ProcessModifiedTime(this ChangeTracker changeTracker)
{
foreach (var item in changeTracker.Entries<IModificationTime>().Where(e => e.State == EntityState.Modified))
{
item.CurrentValues[AppConsts.ModificationTime] = DateTime.Now;
}
}
public static void ProcessSoftDelete(this ChangeTracker changeTracker)
{
foreach (var item in changeTracker.Entries<ISoftDelete>().Where(e => e.State == EntityState.Deleted))
{
item.State = EntityState.Modified;
item.CurrentValues[AppConsts.IsDeleted] = true;
item.CurrentValues[AppConsts.DeletionTime] = DateTime.Now;
}
}
}
A livello di livello di servizio o di controller è possibile assegnare ogni volta il valore richiesto ( CreatorUserId
, MofidierUserId
, DeleterUserId
) ma diventa un'attività di routine, molto noiosa .
Ho visto l' implementazione di AspNetBoilerplate , ma ciò che mi preoccupa è che gli sviluppatori rendono il loro DbContext dipendente da Session e altre cose.
public abstract class AbpDbContext : DbContext, ITransientDependency, IShouldInitialize
{
public IAbpSession AbpSession { get; set; }
public IEntityChangeEventHelper EntityChangeEventHelper { get; set; }
public ILogger Logger { get; set; }
public IEventBus EventBus { get; set; }
public IGuidGenerator GuidGenerator { get; set; }
public ICurrentUnitOfWorkProvider CurrentUnitOfWorkProvider { get; set; }
public IMultiTenancyConfig MultiTenancyConfig { get; set; }
...
IMHO, questa è una tipica violazione del Principio di Responsabilità Unica .
Ho provato a esaminare gli intercettori , ma sembra che siano disponibili solo nell'edizione ordinaria (non core) di Entity Framework , ma non sono ancora riuscito a capire come implementare ciò che ho menzionato sopra.
In realtà, sono completamente perso su come gestirlo con Entity Framework Core. Qualcuno può pensare a qualsiasi soluzione a livello di servizio per questo? O forse c'è un modo migliore?
UserId e TenantId qui sono solo pezzi di dati che il tuo servizio di repository (qui un DbContext) ha bisogno. Se un servizio ha bisogno di dati, dovrebbe essere iniettato nel servizio.
Senza DI potresti rendere i parametri del costruttore e dell'IDID TenantID sul tuo DbContext. Con DI si potrebbe iniettare una dipendenza da un servizio che fornisce questi dati.