我们首先使用实体框架代码,我正在遇到问题,试图在我们不想 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);
}
}
}
如果我最终会更改或发现它的问题,我会记住回来更新...