实体框架 6:审计/跟踪更改
Posted
技术标签:
【中文标题】实体框架 6:审计/跟踪更改【英文标题】:Entity Framework 6: audit/track changes 【发布时间】:2014-12-08 22:23:06 【问题描述】:我的核心项目是用 C# 编写的。
我在一个数据库上工作,其中一些表具有“user_mod”和“date_mod”列,用于标记谁以及何时制作了一些 mod,并且与“data_new”和“user_new”相同。
我的问题:有没有办法集中这个并自动插入这些数据,我在其中创建dbContext
的实例?
如果没有,我将使用审计跟踪工具。我见过其中的一些,但有一个问题:所有这些都需要我的模型中的一些代码。但我不想写在我的模型中,因为如果我必须更改它,我会丢失 mods。是否可以在不写入模型文件的情况下对 EF6 使用审计跟踪?怎么样?
编辑:
我尝试覆盖 saveChanges。
public partial class PieEntities : DbContext
public override int SaveChanges(System.Data.Objects.SaveOptions options)
var timestamp = DateTime.Now;
EntityState es = EntityState.Added;
ObjectStateManager o = new ObjectStateManager();
foreach (ObjectStateEntry entry in o.GetObjectStateEntries(EntityState.Added ))
if (entry.Entity.GetType() == typeof(TabImpianti))
TabImpianti impianto = entry.Entity as TabImpianti;
impianto.DATA_INS = timestamp;
impianto.DATA_MOD = timestamp;
string u = mdlImpostazioni.p.UserName;
impianto.USER_INS = u;
impianto.USER_MOD = u;
return base.SaveChanges(options);
更新:我总结了solution here。
【问题讨论】:
Entity Framework DbContext SaveChanges() OriginalValue Incorrect 的可能副本。在这方面还有很多努力。寻找实体框架 + 审计。 @GertArnold 为什么?我不这么认为。此外,这个问题是关于 EF4,我的两个旧版本。 好吧,当我在 *** 上搜索这个主题时,我从一长串点击中随机挑选了一个。它通常相当于覆盖SaveChanges
,这在 EF4 中是相同的。在 EF6 中,您可能会在命令树拦截器领域冒险,但我不确定这会将您带到哪里。
@PieroAlberto 你的 ObjectStateManager 必须来自上下文:从这个(this as IObjectContextAdapter).ObjectStateManager
分配它
关于碱基调用,我不明白它为什么会造成问题。我认为您不需要再次告诉编译器您是从 DbContext 继承的,删除 : DbContext
【参考方案1】:
如果使用 EF6 的 DbContext
,您可以在 SaveChanges
覆盖中使用 ChangeTracker
来查找添加/修改的自定义类型实体,例如 IAuditedEntity。
public interface IAuditedEntity
string CreatedBy get; set;
DateTime CreatedAt get; set;
string LastModifiedBy get; set;
DateTime LastModifiedAt get; set;
public override int SaveChanges()
var addedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
.Where(p => p.State == EntityState.Added)
.Select(p => p.Entity);
var modifiedAuditedEntities = ChangeTracker.Entries<IAuditedEntity>()
.Where(p => p.State == EntityState.Modified)
.Select(p => p.Entity);
var now = DateTime.UtcNow;
foreach (var added in addedAuditedEntities)
added.CreatedAt = now;
added.LastModifiedAt = now;
foreach (var modified in modifiedAuditedEntities)
modified.LastModifiedAt = now;
return base.SaveChanges();
【讨论】:
您的代码看起来很简单,但我刚刚尝试过...我在我的一个表中插入了一个新项目,但它没有输入到 addedEntities 的 for 中。它是如何工作的?我该怎么办? 您要跟踪/审计的实体必须实现IAuditedEntity
我的实体?但我的实体是在模型中定义的......我不想手动修改自动生成的模型。我该怎么做? (请原谅我的问题)
EF 数据库第一个实体用 partial 关键字标记。这使得在不干扰生成代码的情况下分配属性变得容易。只需创建一个新文件AuditedEntries.cs
包含[IAuditedEntity] public partial class TabImpianti
要清楚一点,因为每个实体都实现了IAuditedEntity
接口,所以属性是各个实体的一部分,所以它们被保存到同一个表中对吗?【参考方案2】:
有一种方法可以做到这一点:您可以创建一个与您的对象上下文同名的分部类,并实现对SaveChanges
方法的覆盖。在此覆盖中,您可以查看将推送到数据库的所有更改并进行处理。
您可以按照自己喜欢的方式处理它们,在以下示例中,我创建了一个接口IAutoTimestampEntity
,其中包含创建日期和修改日期。这种类型的任何对象都会随着时间的变化而自动更新。
public override int SaveChanges(System.Data.Objects.SaveOptions options)
var timestamp = DateTime.Now;
foreach (var InsertedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
InsertedAutoTimestampEntity.CreationDate = timestamp;
InsertedAutoTimestampEntity.ModificationDate = timestamp;
foreach (var UpdatedAutoTimestampEntity in ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified).Select(ose => ose.Entity).OfType<IAutoTimestampEntity>())
UpdatedAutoTimestampEntity.ModificationDate = timestamp;
return base.SaveChanges(options);
您可以使用相同的原理,也可以详细查看每个更改实体的类型。不过,我喜欢界面的声明性方面。它允许您显式地公开自动化的一个方面,而不是让它由 EF 层静默完成。
如果您有DbContext
而不是ObjectContext
,请将您的DbContext
转换为IObjectContextAdapter
以访问ObjectStateManager
【讨论】:
不错!!是否也可以看到什么是删除?什么是 InsertedAutoTimestampEntity 和 UpdatedAutoTimestampEntity? InsertedAutoTimeStampEntity 和 UpdatedAutoTimestampEntity 是我在枚举中给实体起的名字,所以只是命名。 关于删除,这里是 EntityState 枚举,您可以看到已删除以及您可以跟踪的其他状态:msdn.microsoft.com/en-us/library/… 我添加了对 System.entity 的引用。但它说“ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added)”它不是静态方法,我必须实例化它。为什么你的代码不是这样的? 如果您使用的是DbContext
而不是ObjectContext
,请将您的DbContext
转换为IObjectContextAdapter
以访问ObjectStateManager
【参考方案3】:
补充来自@AlaaMasoud 的答案。
使用CreatedDate
和UpdatedDate
:
interface IEntityDate
DateTime CreatedDate get; set;
DateTime UpdatedDate get; set;
public abstract class EntityBase<T1>: IEntityDate
public T1 Id get; set;
public virtual DateTime CreatedDate get; set;
public virtual string CreatedBy get; set;
public virtual DateTime UpdatedDate get; set;
public virtual string UpdatedBy get; set;
public override int SaveChanges()
var now = DateTime.Now;
foreach (var changedEntity in ChangeTracker.Entries())
if (changedEntity.Entity is IEntityDate entity)
switch (changedEntity.State)
case EntityState.Added:
entity.CreatedDate = now;
entity.UpdatedDate = now;
break;
case EntityState.Modified:
Entry(entity).Property(x => x.CreatedDate).IsModified = false;
entity.UpdatedDate = now;
break;
return base.SaveChanges();
要处理CreatedBy
和UpdatedBy
,我使用DbContext
的包装器,如下所示:
public interface IEntity
DateTime CreatedDate get; set;
string CreatedBy get; set;
DateTime UpdatedDate get; set;
string UpdatedBy get; set;
public interface ICurrentUser
string GetUsername();
public class ApplicationDbContextUserWrapper
public ApplicationDbContext Context;
public ApplicationDbContextUserWrapper(ApplicationDbContext context, ICurrentUser currentUser)
context.CurrentUser = currentUser;
this.Context = context;
public class ApplicationDbContext : DbContext
public ICurrentUser CurrentUser;
public override int SaveChanges()
var now = DateTime.Now;
foreach (var changedEntity in ChangeTracker.Entries())
if (changedEntity.Entity is IEntity entity)
switch (changedEntity.State)
case EntityState.Added:
entity.CreatedDate = now;
entity.UpdatedDate = now;
entity.CreatedBy = CurrentUser.GetUsername();
entity.UpdatedBy = CurrentUser.GetUsername();
break;
case EntityState.Modified:
Entry(entity).Property(x => x.CreatedBy).IsModified = false;
Entry(entity).Property(x => x.CreatedDate).IsModified = false;
entity.UpdatedDate = now;
entity.UpdatedBy = CurrentUser.GetUsername();
break;
return base.SaveChanges();
...
来源:
https://***.com/a/53669556/3850405
【讨论】:
以上是关于实体框架 6:审计/跟踪更改的主要内容,如果未能解决你的问题,请参考以下文章
如何使用trackerenableddbcontext在asp.net mvc5和代码中的实体框架中实现审计跟踪
为啥实体框架 System.Data.Entity.Core.Objects.RelationshipEntry 错误? (用于更改跟踪)