2010-09-03 51 views
1

我有某些实体具有LastUpdated和LastUpdatedBy等审计跟踪元素。我正在寻找确定在模型更改时将这些字段更新为当前日期和时间以及当前用户的最合适方法。注入对模型数据的更改

最简单的实现是在我更​​新objectcontext之前在我的控制器中影响此更改,但这会导致大量重复的代码。我可以重构这一点,并可能创建一个帮助器方法,我可以调用并传递模型,从而将事情减少到我的控制器中的一行代码,但我真的宁愿这是自动的,控制器代码不必担心的事情关于。

有没有人接触过这个问题?你的解决方案是什么?你有什么建议?

(PS MVC和EF小白所以有可能是我缺少一个框架,类型选项)

+0

请继续关注,我已经完成了这个没有T4挂钩到新的可覆盖的SaveChanges事件。 – jfar 2010-09-03 23:51:48

回答

0

我做这样的东西,我用T4模板。参见:Entity Framework Trigger Like Auditing

基本上我只是让所有的实体扩展一个接口,然后在SaveChanges遍历所有“IAuditable”并设置更新/插入日期。

为我们工作得很好,但我们也经历了每一个实体,确保审计字段具有相同的名称。一旦你这样做,很容易为那些包含审计字段的表自动生成自定义代码。谢谢有道理?

2

我遵循了与@Nix类似的模式,只有我没有使用T4,因为我更喜欢代码优先的开发,而不是设计师。如果您有一个名为MyDbContextContext,您可以对其进行部分分类以覆盖SaveChanges()方法。我也有一个我所需要的所有实体扩展的类。

public interface IAuditable 
{ 
    User CreatedBy { get; set; } 
    DateTime? DateCreated { get; set; } 
    User ModifiedBy { get; set; } 
    DateTime? DateModified { get; set; } 
    User DeletedBy { get; set; } 
    DateTime? DateDeleted { get; set; } 
} 

// Classes that implement the IAuditable here. 

public class User : EntityObject 
{ 
    public string Username { get; set; } 
    public string DisplayName { get; set; } 
    // etc... 
} 

partial class MyDbModel 
{ 
    public override int SaveChanges(SaveOptions options) 
    { 

     // Search all added, modified or deleted entities. 
     var entries = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted); 

     foreach (var entry in entries) 
     { 

      var auditable = entry.Entity as IAuditable; 

      if (auditable != null) 
      { 
       if (entry.State == EntityState.Added) 
       { 
        auditable.CreatedBy = null; // TODO - Get current user. 
        auditable.DateCreated = DateTime.Now; 
        auditable.ModifiedBy = null; // TODO - Same as CreatedBy? 
        auditable.DateModified = DateTime.Now; 
       } 
       else if (entry.State == EntityState.Modified) 
       { 
        auditable.ModifiedBy = null; // TODO - Get current user. 
        auditable.DateModified = DateTime.Now; 
       } 
       else if (entry.State == EntityState.Deleted) 
       { 
        auditable.DeletedBy = null; // TODO - Get current user. 
        auditable.DateDeleted = DateTime.Now; 
       } 
      } 
     } 


     return base.SaveChanges(options); 
    } 
} 
+0

我打算发布相同的代码,除了我更喜欢反射与实现接口。 – jfar 2010-09-04 01:40:18

+0

@jfar - 我不会去反射路线的唯一原因是性能影响。 – TheCloudlessSky 2010-09-04 13:44:49

+0

性能影响可以忽略不计。反思并不慢。 1000次迭代测试:反射:12毫秒,本机:2毫秒。没什么大不了的。我估计一个大的工作单元会一次更新10个实体,反思1ms,本机0ms。我相信你的用户不会在乎1ms。 – jfar 2010-09-04 14:23:43