Implementando auditoría a nuestras tablas con Entity Framework

En esta entrada vamos a automatizar la auditoria a nuestras tablas usando el Entiy Framework mediante el uso de una interface.

Rodríguez Patiño, Eduardo
5,764 lecturas
Rodríguez Patiño, Eduardo
Hemos migrado hace poco nuestras publicaciones del blog antiguo. Si crees que esta se encuentra incompleta o sin coherencia deja un comentario para restaurarla manualmente.

Es una buena práctica auditar nuestras tablas, es decir llevar un control de que usuario y cuando agrego o modifico un registro en nuestra tabla, lo común es crear 4 campos adicionales.

CreadPor INT,
Creado DATETIME,
ActualizadoPor INT,
Actualizado DATETIME

Creando la interface IAuditable

Ahora vamos a crear una interface, está solo va a contener los campos de auditoría.

public interface IAuditable
{
    int CreadoPor { get; set; }
    DateTime CreadoFecha { get; set; }
    int ActualizadoPor { get; set; }
    DateTime ActualizadoFecha { get; set; }
}

Implementando la interface a nuestra entidad

Bien, ya tenemos resuelto la mitad del problema. Ahora tenemos que agregar la implementación a las entidades que queremos auditar, veamos un ejemplo simple:

[Table("Alumno")]
public partial class Alumno : IAuditable
{
    public int id { get; set; }

    [Required]
    [StringLength(50)]
    public string Nombre { get; set; }

    [Required]
    [StringLength(100)]
    public string Apellido { get; set; }

    public int Sexo { get; set; }

    #region Auditoria
    public int CreadoPor { get; set; }
    public DateTime CreadoFecha { get; set; }
    public int ActualizadoPor { get; set; }
    public DateTime ActualizadoFecha { get; set; }
    #endregion
}

NOTA: las entidades que implemente dicha interface no vayan olvidar crear los campos de auditoria en la tabla de la base de datos.

Implementando la auditoría automaticamente

Debemos hacer un override al método SaveChanges() en nuestro contexto, me refiero a la clase que maneja los DbSet.

public override int SaveChanges()
{
    Auditar();
    return base.SaveChanges();
}

public void Auditar()
{
    var modifiedEntries = ChangeTracker.Entries().Where(
        x => x.Entity is IAuditable && (x.State == System.Data.Entity.EntityState.Added
             || x.State == System.Data.Entity.EntityState.Modified));

    foreach (var entry in modifiedEntries)
    {
        IAuditable entity = entry.Entity as IAuditable;
        if (entity != null)
        {
            var fecha = DateTime.Now;
            var usuario = SessionHelper.GetUser();

            if (entry.State == EntityState.Added)
            {
                entity.CreadoFecha = fecha;
                entity.CreadoPor = usuario;
            }
            else
            {
                base.Entry(entity).Property(x => x.CreadoFecha).IsModified = false;
                base.Entry(entity).Property(x => x.CreadoPor).IsModified = false;
            }

            entity.ActualizadoFecha = fecha;
            entity.ActualizadoPor = usuario;
        }
    }
}

En resumen lo que hago ahí es identificar la entidad actual que se está trabajando, si esta implementa la interface IAuditable, va a setear los campos de auditoría por nosotros.

Alternativa para auditar

Conversando con unos colegas me han dado otra alternativa. En vez de usar una interface mejor creamos una clase llamada Auditable y hacer que herede de las entidades que deseamos auditar. Luego en el método SaveChanges() deberíamos validar si la entidad con la que estamos trabajando hereda de Auditable. Finalmente, lo que hemos logrado es evitar copiar los propiedades de auditoria en nuestras entidades, ¿Por qué?, porque estamos heredeando de la clase Auditable, esta contiene dichas propiedades.

Les comparto el GitHub:

¿Te gustó nuestra publicación?
Suscríbete a nuestro boletín