sǝɯ*_*ɯɐſ 5 .net entity-framework code-first navigational-properties
我们正在使用实体框架代码优先,我遇到了在我们不希望的情况下尝试回滚插入,更新和删除实体更改的问题SaveChanges()
.
具体来说,我有一个datagridview,我用它作为TableEditor,来更改一些辅助表.datagridview绑定到DbSet<TEntity>
.
我的回滚更新似乎工作正常,我只是将currentValues设置回其OriginalValues,并将状态更改为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?");
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
foreach (var entity in db.CertificationDecisions)
{
DbEntityEntry entry = db.Entry(entity );
if (entry.State != EntityState.Unchanged)
{
RollbackChanges(entry);
}
}
Run Code Online (Sandbox Code Playgroud)
任何想法为什么导航属性会从记录中消失?(或者我可以做些什么来让他们回来?)
Refresh
:
我正在使用DbContext,所以我用这一行替换了我的回滚方法:
((IObjectContextAdapter)db).ObjectContext.Refresh(RefreshMode.StoreWins, db.CertificationDecisions);
Run Code Online (Sandbox Code Playgroud)
但是,这似乎没有重新加载上下文,因为记录仍然缺失...我使用Refresh
错了吗?
这听起来像是我的问题的可能解决方案,但我仍然想知道为什么导航属性将被删除?
这并不是我问题的真正答案,但到目前为止似乎对我有用的替代方案(如果有人正在寻找这个问题的答案):
基本上,我创建一个新上下文并将一个实体从新上下文传递到我的表单。如果我取消表单,我只需处理上下文,因此不会保存任何更改(无需回滚)。如果我保存表单,那么我会保存新上下文中的更改,但随后我需要使原始上下文知道这些更改。
所以我使用.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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我最终改变了这个或发现了问题,我会尽量记得回来更新......