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

时间:2012-05-08 16:11:18

标签: c# entity-framework

我想在项目中维护所有已修改的记录和已删除的记录,并使用“状态”列跟踪其状态。下面是我第一次尝试的代码,但由于显而易见的原因,我似乎无法将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();
    }

3 个答案:

答案 0 :(得分:2)

我不确定我是否理解你在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将被创建并保存为新对象,表示修改前的状态。

我希望转化为ITrackable应该有效,因为ToObject()会创建一个由OriginalValues字典表示的类型的对象,并且必须是ITrackable因为您通过此接口过滤了ChangeTracker.Entries枚举。

以上是未经测试的,我不确定它是否可行。

修改

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

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

答案 1 :(得分:2)

我一直在寻找你应该如何覆盖SaveChanges()来实现类似的目标

像这样投射会更容易;

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

答案 2 :(得分:0)

虽然与您使用的方法不完全相同,但我使用存储库模式。应用程序的其余部分只是实例化存储库类,并调用Save(objToSave)Delete(objToDelete)或类似的。现在,执行过程与实际数据存储断开,我可以采取适当的措施:更新ModifyDate,更改Status等。如果您将DataContext暴露给其余的应用程序,很难控制引擎盖下的细节。