我正在尝试处理批量插入过程中的情况,其中可能存在具有相同主键的实体,这当然会使 SaveChanges 抛出异常。
这就是我所拥有的:
try
{
_context.SaveChanges();
_context.Dispose();
_context = null;
_context = SelectContext<T>();
_commitCount = 0;
}
catch (System.Data.UpdateException updateEx)
{
//Remove from _context all the entries that errored in the SaveChange() process...
if (updateEx.StateEntries != null)
{
foreach (ObjectStateEntry stateEntry in updateEx.StateEntries)
{
if ((System.Data.EntityState)stateEntry.Entity.GetType().GetProperty("EntityState").GetValue(stateEntry.Entity, null) != System.Data.EntityState.Detached)
{
_context.Detach(stateEntry.Entity);
}
}
}
//Save context changes again this time without erroneous entries...
try
{
_context.SaveChanges();
_context.Dispose();
_context = null;
_context = SelectContext<T>();
_commitCount = 0;
}
catch (Exception ex)
{
//Welp, at the point, I'm clueless...
}
如果我查看ObjectStateManager,确实删除了实体(计数下降了foreach循环迭代的次数。)
但它仍然在第二次尝试时抛出一个例外,抱怨一个骗局PK。
我认为分离一个实体是相同的,如果它从来没有在上下文中。我还需要做点什么吗?
感谢。
答案 0 :(得分:1)
Deatch
无法完全撤消更改。根据msdn doc“只删除实体;如果有任何相关对象被同一个ObjectStateManager跟踪,那么这些对象将不会自动分离。”
仅删除您传递给分离的实体。其他更改将导致失败。你的db会不会有争用?如果此应用程序是唯一对数据库进行更改的应用程序,则可以使用context.Refresh(RefreshMode.StoreWins, object);
撤消更改,否则会更复杂。
你必须做这样的事情;
var entry = context.ObjectStateManager.GetObjectStateEntry(((IEntityWithKey)object).EntityKey);
for (int i = 0; i < entry.OriginalValues.FieldCount; i++)
{
entry.CurrentValues.SetValue(i, entry.OriginalValues[i]);
}
entry.AcceptChanges();
上面的代码使用ObjectSateManager
将所有修改过的对象返回到原始状态,之后context.SaveChanges();
shoudl成功。
您也可能会发现这个有用的http://dotnetadventurer.blogspot.com/2010/09/discarding-changes-to-objectcontext-in.html我没有尝试过他的代码而且我通常会以不同的方式初始化我的上下文,所以我不确定它是否适用于您的示例,但它非常简单,如果有的话,这是我要去的路线。
答案 1 :(得分:1)
这就是我最终在我的案例中做的事情:
_context.ObjectStateManager.ChangeObjectState(stateEntry.Entity, System.Data.EntityState.Unchanged);
_context.ApplyOriginalValues<T>(entityType, (T)stateEntry.Entity);
_context.Detach(stateEntry.Entity);
之后,我可以保存上下文更改。