In Entity Framework Core, è possibile sovrascrivere il metodo SaveChanges
/ SaveChangesAsync
in DbContext
e in base a stati diversi come: EntityState.Added
o EntityState.Modified
o EntityState.Deleted
, è possibile creare una soluzione di controllo su quando e chi ha creato, modificato o eliminato determinati record. È possibile salvare lo stato dell'entità prima e dopo l'azione. Tutto bene funziona perfettamente!
Possiamo fare qualcosa di simile per le azioni read / query / select / view?
Ho scavato un po 'e ho scoperto che l'esecuzione effettiva di IQueryable
è eseguita da EntityQueryProvider : IAsyncQueryProvider, IQueryProvider
.
Quindi ... devi eseguire l'override di EntityQueryProvider
per eseguire la registrazione:
public class LoggingQueryProvider : EntityQueryProvider
{
public LoggingQueryProvider(IQueryCompiler queryCompiler) : base(queryCompiler) { }
public override object Execute(Expression expression)
{
var result = base.Execute(expression);
//log
return result;
}
public override TResult Execute<TResult>(Expression expression)
{
var result = base.Execute<TResult>(expression);
//log
return result;
}
public override IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
var result = base.ExecuteAsync<TResult>(expression);
//log
return result;
}
public override Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
var result = base.ExecuteAsync<TResult>(expression, cancellationToken);
//log
return result;
}
}
e lo si registra quando si configura DbContext in StartUp.ConfigureServices(IServiceCollection services)
services.AddDbContext<XPContext>(builder =>
builder
.UseSqlServer(Configuration["TryDBConnectionString"])
.ReplaceService<IAsyncQueryProvider, LoggingQueryProvider>()
);
Non è abbastanza semplice, ma dovresti essere in grado di ottenere alcune informazioni dall'espressione, come il tipo di entità, e ovviamente hai accesso al risultato reale. Le cose sembrano un po 'più complicate per i metodi asincroni, ma ...
La maggior parte delle strategie si basa sulla sostituzione di SaveChanges()
per controllare i dati, ma è possibile accedere ad altri dati anche sovrascrivendo il metodo Dispose()
.
Quando i dati vengono interrogati dal database, vengono aggiunti a dbContext e se vengono letti ma non modificati, dovrebbe avere EntityState.Unchanged
.
Supponendo un tipico ambito DbContext
stile app Web di una nuova istanza per richiesta, una query per id significherebbe che c'era una singola voce in ChangeTracker
con quello stato quando DbContext
è stato eliminato.
Potresti provare qualcosa del genere:
public override void Dispose()
{
var unchanged = ChangeTracker.Entries()
.Where(x => x.EntityState == EntityState.Unchanged);
// log your unchanged entries here
base.Dispose();
}
Questo non è del tutto infallibile, poiché potresti recuperare i dati da alcune tabelle come parte della convalida durante un processo di creazione / aggiornamento o potresti condividere un contesto attraverso più repository, quindi devi considerare attentamente quali entità devono essere controllate e quali schemi di accesso usi