我正在将一个旧项目移植到ASP.NET 5和Entity Framework 7.我已经使用数据库第一种方法(DNX scaffold)来创建模型.
旧项目基于实体框架4,审计跟踪是通过覆盖以下SaveChanges
方法实现的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); }
我的问题是,我如何在Entity Framework 7中实现这一点?我必须先采用代码方法吗?
基本上你有两种方法来实现这个目标:
使用ChangeTracker API(EF 6+):
这是我们目前在EF 6中的方式,它仍然有效并适用于EF 7:
首先,您必须确保您的实体正在为审计字段实现通用接口:
public interface IAuditableEntity { int? CreatedById { get; set; } DateTime Created { get; set; } int? ModifiedById { get; set; } DateTime Modified { get; set; } }
然后,您可以覆盖SaveChanges并使用审计值更新每个公共字段:
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() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified); foreach (EntityEntry 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(); }
使用EF 7新的"阴影属性"功能:
阴影属性是实体类中不存在的属性.这些属性的值和状态仅在Change Tracker中维护.
换句话说,审核列不会在您的实体上公开,与上面的实体相比,它们似乎是一个更好的选择.
要实现阴影属性,首先必须在实体上配置它们.比方说,你有一个需要有一些审计列的User对象:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().Property ("CreatedById"); modelBuilder.Entity ().Property ("Created"); modelBuilder.Entity ().Property ("ModifiedById"); modelBuilder.Entity ().Property ("Modified"); }
配置完成后,您现在可以在SaveChanges()覆盖上访问它们并相应地更新它们的值:
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() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified); foreach (EntityEntry 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(); }
最后的想法:
为了实现像审计列这样的东西,我将采用阴影属性方法,因为这些是交叉关注的问题,并不一定属于我的域对象,因此以这种方式实现它们将使我的域对象保持良好和干净.