我应该如何覆盖 DbContext 上的 SaveChanges() 方法,以便使用 EF 4.3 维护已删除/修改的记



我想维护项目中所有已修改的记录和已删除的记录,并使用"状态"列跟踪其状态。 下面是我第一次尝试的代码,但由于显而易见的原因,我似乎无法OriginalValues.ToObject()转换为 DbEntityEntry。 我应该如何完成此操作?

    public override int SaveChanges()
    {
        var now = DateTime.Now;
        var currentUser = HttpContext.Current.User.Identity.Name;
        var trackedEntities = ChangeTracker.Entries<ITrackable>();
        foreach (var trackedEntity in trackedEntities)
        {
            switch(trackedEntity.State)
            {
                case System.Data.EntityState.Added:
                    trackedEntity.Entity.CreatedDate = now;                        
                    trackedEntity.Entity.CreatedBy = currentUser;                        
                    trackedEntity.Entity.Status = Status.Active;
                    break;
                case System.Data.EntityState.Modified:                        
                    var originalEntity = trackedEntity.OriginalValues.ToObject() as DbEntityEntry<ITrackable>;                        
                    originalEntity.Entity.ModifiedDate = now;
                    originalEntity.Entity.ModifiedBy = currentUser;
                    originalEntity.Entity.Status = Status.Modified;
                    var newEntity = trackedEntity.CurrentValues.ToObject() as DbEntityEntry<ITrackable>;
                    newEntity.State = System.Data.EntityState.Added;
                    newEntity.Entity.Status = Status.Active;                                                
                    break;
                case System.Data.EntityState.Deleted:
                    trackedEntity.State = System.Data.EntityState.Modified;
                    trackedEntity.Entity.Status = Status.Deleted;
                    break;                            
            }                
        }
        return base.SaveChanges();
    }

我不确定我是否正确理解了您在Modified情况下要实现的目标。但我的理解是,ToObject()创建一个全新的对象,并用OriginalValues字典中的属性值填充它。因此,originalEntity 不会附加到上下文中,当变量超出范围时,只会进行垃圾回收,没有任何影响。

因此,在保存修改之前,是否不需要将originalEntity作为新添加的实体保存到数据库中以保存最新版本?

我会试试这个:

case System.Data.EntityState.Modified:                        
    var originalEntity = trackedEntity.OriginalValues.ToObject() as ITrackable;
    originalEntity.ModifiedDate = now;
    originalEntity.ModifiedBy = currentUser;
    originalEntity.Status = Status.Modified;
    Entry(originalEntity).Status = System.Data.EntityState.Added;
    trackedEntity.Entity.Status = Status.Active;
    break;

无论如何,trackedEntity都会被保存,因为它处于状态Modified并且originalEntity将被创建并保存为表示修改前状态的新对象。

我希望 cast to ITrackable 应该工作,因为ToObject()创建一个由OriginalValues字典表示的对象,并且它必须是ITrackable,因为您通过此接口过滤ChangeTracker.Entries枚举。

以上未经测试,我不确定它是否有效。

编辑

上面的命名有点令人困惑,因为originalEntity是模型中的实体,而trackedEntityDbEntityEntry<T>。也许将其重命名为originalEntityObject(丑陋(或更好的trackedEntityEntry.

值得一提的是:在进入foreach循环之前调用ChangeTracker.DetectChanges()是绝对必要的(除非您因此使用更改跟踪代理(,否则条目可能不处于正确的最终状态,并且您输入了错误的case节或根本没有节(当状态Unchanged但仍更改了属性时(。POCO 更改是通过与 OriginalValues 中的快照进行比较来检测的,最后一次比较是在循环之后base.SaveChanges完成的,为时已晚。(另请参阅此处答案中的"编辑 2":https://stackoverflow.com/a/6157071/270591。

我正在寻找如何覆盖 SaveChanges(( 以实现类似的目标

这样投射会更容易;

((ITrackable)trackedEntity.Entity).CreatedDate = now;

虽然与您使用的方法不同,但我为此使用了存储库模式。 应用程序的其余部分只是实例化存储库类,并调用Save(objToSave)Delete(objToDelete)或类似内容。 现在执行过程与实际数据存储断开连接,我可以采取适当的操作:更新ModifyDate、更改Status等。 如果要将DataContext暴露给应用程序的其余部分,则很难控制幕后的细节。

最新更新