如何回滚实体删除而不会丢失导航属性



我们首先使用实体框架代码,我正在遇到问题,试图在我们不想 SaveChanges()时插入,更新和删除实体更改。

具体来说,我有一个datagridview,我将其用作表格机,以更改某些辅助表。DataGridView绑定到DbSet<TEntity>

我的更新回滚似乎正常,我只是将CurrentValues设置为返回其原始值,然后将状态更改为unchanged

当记录插入gridview(但没有保存的更改)时,它从未显示在实体类中,我再也看不到它……所以我想它不会到达DBSET,并且不需要回滚?

但是我的主要问题在于删除

据我了解,当记录被"删除"(例如tableData.Remove(currentItem);)时,删除只是标记,直到调用SaveChanges。因此,如果我将状态从deleted更改为unchanged,那应该处理回滚,对吗?

好吧,记录确实再次显示了备份,但是记录的导航属性已经消失了!(即包含外键的列和与其他实体的关系)。为什么这是?!

这是我到目前为止所拥有的:

    public void RollbackChanges(DbEntityEntry entry)
    {
        if (entry.State == EntityState.Modified)
        {
            foreach (var propertyName in entry.OriginalValues.PropertyNames)
            {
                entry.CurrentValues[propertyName] = entry.OriginalValues[propertyName];
            }
            entry.State = EntityState.Unchanged;
        }
        else if (entry.State == EntityState.Deleted)
        {
            entry.State = EntityState.Unchanged;
        }
        else if ((entry.State == EntityState.Added) || (entry.State == EntityState.Detached))
        {
            MessageBox.Show("I don't think this ever happens?");
        }
    }

示例用法:

    foreach (var entity in db.CertificationDecisions)
                {
                    DbEntityEntry entry = db.Entry(entity );
                    if (entry.State != EntityState.Unchanged)
                    {
                        RollbackChanges(entry);
                    }
                }

有什么想法为什么导航属性会从记录中消失?(或我能做什么才能让他们回来?)


编辑:@chris关于使用Refresh

我正在使用dbcontext,所以我用此行替换了回滚方法:

((IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.StoreWins, db.CertificationDecisions);

但是,这似乎并没有重新加载上下文,因为记录仍然缺少...我是否使用Refresh错误?

这听起来像是解决我的问题的可能解决方案,但是我仍然想知道为什么要删除导航属性?

有什么想法为什么导航属性会从记录中消失?

由于外交关系,导航属性很可能被删除。让我们参加以下课程:

public class Dog
{
  public guid ID { get; set; }
  public string Title { get; set; }
}
public class Person
{
  public guid ID { get; set; }
  public ICollection<Dog> FavoriteDogs { get; set; }
}

在数据库中,Favoritedogs的集合是一个表明人和狗的表,但由导航属性自动隐藏。当将 parent 状态设置为删除时,EF会自动将参考实体标记为已删除。如果 parent 实体设置为不变,则实体框架将不会将这些参考实体设置为不变,因为这样做不需要参考完整性(仅用于删除操作)。

或我可以做些什么才能使他们回来?

当前EF中没有自动化过程可以执行此操作。我认为甚至没有一种更改参考实体的手动方法。而新的实体框架5并未公开查看或更改DbRefrenceEntry的状态的任何方法。

也许尝试dbreferenceentry.reload。

这并不是我问题的答案,而是到目前为止似乎对我有用的替代方案(以防有人在寻找这个问题的答案):p>基本上,我创建了一个新的上下文,并将实体从新上下文传递给我的表单。如果i 取消表格,我只是简单地处理上下文,因此没有保存更改(无需回滚)。如果我保存表单,那么我将保存新上下文中的更改,但是然后我需要让我的原始上下文意识到更改。

因此,我使用.Refresh,它似乎成功地找到了新实体,但没有删除已删除的实体。因此,我循环浏览实体,并将它们与数据库值进行比较。

如果数据库返回" null",我们知道该实体已在数据库中删除,需要从上下文中删除。(但是,我无法在循环中将其删除,因为试图在列举其同时更改上下文的内容会导致错误,因此,我将条目添加到列表中以从上下文中以单独的循环中的上下文删除。)

以下是代码:
(注意:我不能保证这是一个很好的解决方案,但似乎对我有用)

            using (FmlaManagementContext auxDb = new FmlaManagementContext())
            {
                AuxiliaryTableEditor<State> statesTableEditor = new AuxiliaryTableEditor<State>(auxDb.States);
                if (statesTableEditor.ShowDialog() != DialogResult.OK)
                {
                    auxDb.Dispose();
                }
                else
                {
                    auxDb.SaveChanges();
                    auxDb.Dispose();
                    //refresh to pick up any new
                    ((IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.StoreWins, db.States);
                    //loop through to remove deleted
                    List<State> nulls = new List<State>();
                    foreach (State state in db.States.Local)
                    {
                        DbEntityEntry entry = db.Entry(state);
                        DbPropertyValues databaseValues = entry.GetDatabaseValues();
                        if (databaseValues == null)
                        {
                            nulls.Add(state); 
                        }
                    }
                    foreach (State state in nulls)
                    {
                        db.States.Remove(state);
                    }
                }
            }

如果我最终会更改或发现它的问题,我会记住回来更新...

最新更新