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();
    }
4

3 回答 3

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(ugly) 或 better trackedEntityEntry

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

于 2012-05-08T17:48:35.487 回答
2

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

像这样投射会更容易;

((ITrackable)trackedEntity.Entity).CreatedDate = now;
于 2012-12-11T16:08:39.020 回答
0

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

于 2012-05-08T17:58:36.143 回答