En Entity Framework Core, puede anular el método SaveChanges / SaveChangesAsync en DbContext y en función de diferentes estados como: EntityState.Added o EntityState.Modified o {{X5} }, puede crear alguna solución de Auditoría sobre cuándo y quién creó, modificó o eliminó ciertos registros. Puede guardar el estado de la entidad antes y después de la acción. Todo bien aquí funciona perfecto!

¿Podemos hacer algo similar para leer / consultar / seleccionar / ver acciones?

4
user2818430 21 oct. 2017 a las 23:12

3 respuestas

La mejor respuesta

Cavé un poco y descubrí que la ejecución real de IQueryable la realiza EntityQueryProvider : IAsyncQueryProvider, IQueryProvider.

Entonces ... anula el valor predeterminado EntityQueryProvider para hacer el registro:

   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;
        }
    }

Y lo registra al configurar DbContext en StartUp.ConfigureServices(IServiceCollection services)

    services.AddDbContext<XPContext>(builder =>
        builder
        .UseSqlServer(Configuration["TryDBConnectionString"])
        .ReplaceService<IAsyncQueryProvider, LoggingQueryProvider>()
    );

No es del todo sencillo, pero debería poder obtener información de la expresión, como el tipo de entidad, y obviamente tiene acceso al resultado real. Las cosas parecen un poco más complicadas para los métodos asíncronos, pero ...

3
Stefan Balan 28 oct. 2017 a las 15:07

Sugeriría iniciar sesión en un nivel superior. Por ejemplo, si está utilizando un WebApi, puede iniciar sesión en el nivel de canalización OWIN, registrando así las solicitudes de información.
El registro más bajo termina en segundo lugar adivinar y volver a iterar a través de datos que son feos y que terminarán contribuyendo a las ineficiencias.

0
Quibblesome 25 oct. 2017 a las 11:08

La mayoría de las estrategias se basan en anular SaveChanges() para auditar datos, pero también puede acceder a otros datos anulando el método Dispose().

Cuando los datos se consultan desde la base de datos, se agregan a dbContext y, si se leen pero no se modifican, deberían tener EntityState.Unchanged.

Suponiendo un alcance típico de estilo de aplicación web DbContext de una nueva instancia por solicitud, una consulta por id significaría que hubo una sola entrada en ChangeTracker con ese estado cuando se desecha DbContext .

Podrías probar algo como esto:

public override void Dispose()
{
    var unchanged = ChangeTracker.Entries()
          .Where(x => x.EntityState == EntityState.Unchanged);

    // log your unchanged entries here

    base.Dispose();
 }

Esto no es totalmente infalible, ya que puede recuperar datos de algunas tablas como parte de la validación durante un proceso de creación / actualización, o puede compartir un contexto a través de múltiples repositorios, por lo que debe considerar qué entidades necesitan una auditoría cuidadosa y qué patrones de acceso utiliza

1
ste-fu 25 oct. 2017 a las 11:03