我正在根据Entity Framework中Context对象中跟踪的更改编写AuditLog。
我需要能够拦截对Context.SaveChanges()
的调用,然后我遍历Context.ChangeTracker.Entries()
并将这些调用记录到我的AuditLog。
我需要能够在DbContext
本身上执行此操作,因为我可以直接通过我的UnitOfWork直接获取DbContext
和PerWebRequest。
我试图通过装饰器解决这个问题,这对我不起作用!
public class AuditLogSaveChangesInKNContextDecorator : DbContext
{
DbContext _context;
IHandleCommand<AddAuditLogEntriesFromTrackedChangesAndSaveChangesCommand> _handler;
public AuditLogSaveChangesInKNContextDecorator(DbContext context,
IHandleCommand<AddAuditLogEntriesFromTrackedChangesAndSaveChangesCommand> handler)
{
_context = context;
_handler = handler;
}
public override int SaveChanges()
{
var changes = base.SaveChanges();
_handler.Handle(new AddAuditLogEntriesFromTrackedChangesAndSaveChangesCommand {
Context = _context
});
return changes;
}
}
任何想法?
答案 0 :(得分:9)
你在做什么对我来说似乎很对。拦截&#39;的唯一方法对SaveChanges
的调用是通过覆盖该方法;它是虚拟的。例如:
public class MyDbContext : DbContext
{
public event Action<MyDbContext> SavingChanges = _ => { };
public override int SaveChanges()
{
// Notify objects that want to know, that we are gonna save some stuff
this.SavingChanges(this);
// Call the actual SaveChanges method to apply the changes to the database
return base.SaveChanges();
}
}
通过使用事件,我们可以向MyDbContext
添加任何行为(依赖注入),而不必知道该上下文。例如:
container.RegisterPerWebRequest<MyDbContext>(() =>
{
var context = new MyDbContext();
context.SavingChanges += UpdateEntities;
return context;
});
private static void UpdateEntities(MyDbContext db)
{
var addedEntities =
from entry in db.ChangeTracker.Entries()
where entry.State == EntityState.Added
select entry.Entity as IEntity;
db.AuditTrailEntries.AddRange(
from entity in addedEntities
select new AuditTrailEntry
{
EntityId = entity.Id,
Type = entity.GetType().Name
});
}
答案 1 :(得分:1)
您在错误的SaveChanges()
上致电DbContext
。
而不是:
var changes = base.SaveChanges();
您应该使用:
var changes = _context.SaveChanges();
由于_context
是您要跟踪的DbContext
,因此您需要在该项目上进行保存,而不是在装饰器对象上进行保存。