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: