framework for example data c# asp.net-core audit entity-framework-core

c# - for - Registro de auditoría de Entity Framework 7



entity framework vs core data (2)

Estoy trasladando un proyecto anterior a ASP.NET 5 y Entity Framework 7. He utilizado el primer enfoque de la base de datos (andamio DNX) para crear el modelo.

El proyecto anterior se basa en Entity Framework 4 y el seguimiento de auditoría se implementa anulando el método SaveChanges del DbContext :

public override int SaveChanges(System.Data.Objects.SaveOptions options) { int? UserId = null; if (System.Web.HttpContext.Current != null) UserId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault(); foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)) { Type EntityType = entry.Entity.GetType(); PropertyInfo pCreated = EntityType.GetProperty("Created"); PropertyInfo pCreatedById = EntityType.GetProperty("CreatedById"); PropertyInfo pModified = EntityType.GetProperty("Modified"); PropertyInfo pModifiedById = EntityType.GetProperty("ModifiedById"); if (entry.State == EntityState.Added) { if (pCreated != null) pCreated.SetValue(entry.Entity, DateTime.Now, new object[0]); if (pCreatedById != null && UserId != null) pCreatedById.SetValue(entry.Entity, UserId, new object[0]); } if (pModified != null) pModified.SetValue(entry.Entity, DateTime.Now, new object[0]); if (pModifiedById != null && UserId != null) pModifiedById.SetValue(entry.Entity, UserId, new object[0]); } } return base.SaveChanges(options); }

Mi pregunta es, ¿cómo puedo implementar esto en Entity Framework 7? ¿Tengo que tomar el primer enfoque del código?


Básicamente tienes dos formas de lograr esto:

Usando la API ChangeTracker (EF 6+):

Esta es la forma en que lo hacemos actualmente en EF 6 y todavía es válido y funciona para EF 7:

Primero, debe asegurarse de que sus entidades estén implementando una interfaz común para los campos de auditoría:

public interface IAuditableEntity { int? CreatedById { get; set; } DateTime Created { get; set; } int? ModifiedById { get; set; } DateTime Modified { get; set; } }


Luego puede anular SaveChanges y actualizar cada campo común con valores de auditoría:

public override int SaveChanges() { int? userId = null; if (System.Web.HttpContext.Current != null) userId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault(); var modifiedEntries = ChangeTracker.Entries<IAuditableEntity>() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified); foreach (EntityEntry<IAuditableEntity> entry in modifiedEntries) { entry.Entity.ModifiedById = UserId; entry.Entity.Modified = DateTime.Now; if (entry.State == EntityState.Added) { entry.Entity.CreatedById = UserId; entry.Entity.Created = DateTime.Now; } } return base.SaveChanges(); }


Usando EF 7 nueva característica de "Propiedades de sombra":

Las propiedades de sombra son propiedades que no existen en su clase de entidad. El valor y el estado de estas propiedades se mantienen únicamente en Change Tracker.

En otras palabras, las columnas de auditoría no estarán expuestas en sus entidades, lo que parece ser una mejor opción en comparación con la anterior donde debe incluirlos en sus entidades.

Para implementar propiedades de sombra, primero debe configurarlas en sus entidades. Digamos, por ejemplo, que tiene un objeto Usuario que necesita tener algunas columnas de auditoría:

protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>().Property<int>("CreatedById"); modelBuilder.Entity<User>().Property<DateTime>("Created"); modelBuilder.Entity<User>().Property<int>("ModifiedById"); modelBuilder.Entity<User>().Property<DateTime>("Modified"); }


Una vez configurado, ahora puede acceder a ellos en SaveChanges () anular y actualizar sus valores en consecuencia:

public override int SaveChanges() { int? userId = null; if (System.Web.HttpContext.Current != null) userId = (from user in Users.Where(u => u.UserName == System.Web.HttpContext.Current.User.Identity.Name) select user.Id).SingleOrDefault(); var modifiedBidEntries = ChangeTracker.Entries<User>() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified); foreach (EntityEntry<User> entry in modifiedBidEntries) { entry.Property("Modified").CurrentValue = DateTime.UtcNow; entry.Property("ModifiedById").CurrentValue = userId; if (entry.State == EntityState.Added) { entry.Property("Created").CurrentValue = DateTime.UtcNow; entry.Property("CreatedById").CurrentValue = userId; } } return base.SaveChanges(); }


Pensamientos finales:

Para implementar algo así como las columnas de auditoría, tomaré el enfoque de Shadow Properties ya que estas son cuestiones transversales y no necesariamente pertenecen a los objetos de mi dominio, por lo que al implementarlas de esta forma mantendré mis objetos de dominio limpios y agradables.


He trabajado en una biblioteca que podría ayudar.

Eche un vistazo a la biblioteca Audit.EntityFramework , intercepta SaveChanges() y es compatible con las versiones de EF Core.