作为我工作中的新手,我为一位离开公司的同事负责该项目。这是他的项目,所以这使所有的工作变得复杂,因为我对所有事情都很孤单,而且随着你的进展我学习了EF。该项目是一个客户端 - 服务器应用程序,使用EF6,UoW和存储库方法。
让我概述一下这个问题。存储库
中的服务器端有一个方法MyEntity SaveMyEntity(MyEntity myEntity)
{
//Do some validation before save - call stored procedure
//If fails throw exception
using(var context = new SomeContext())
{
//little bit of code for imagination how implementation looks like
context.my_entity_context_base.Attach(myEntity);
context.SyncObjectState(myEntity, myEntity.ObjectState);
context.SaveChanges();
//...
if (myEntity.EntityB != null && myEntity.EntityB.Count > 0)
{
foreach (var u in myEntity.EntityB.ToList())
{
context.entity_b_context_base.Attach(u);
context.SyncObjectState(u, u.ObjectState);
}
context.SaveChanges();
}
if (myEntity.EntityC != null && myEntity.EntityC.Count > 0)
{
foreach (var t in myEntity.EntityC.ToList())
{
context.entity_c_context_base.Attach(t);
context.SyncObjectState(t, t.ObjectState);
}
context.SaveChanges();
}
// and so on ..
}
//Validation after save - stored procedur is called
//If fails throws exception
//If validate_after_save fails there is rollback on DB side.
base.ExecuteStoredProcedure("validate_after_save", ref parameters, ref errorText);
if (!string.IsNullOrEmpty(errorText))
{
throw new OwnException("Save failed: " + errorText);
}
return this.GetMyEtity(myEntity.id);
}
当没有异常被抛出时一切都很好但是在保存抛出之后验证时,客户端没有得到实际的实体。在我之前发现的某些情况下,这确实是个问题。例如,我想要保存实体。保存抛出ex之后的验证(因此客户端不接收实体)。所以我会改变一些东西并再次保存。因为保存之后的先前验证会引发异常,所以客户端仍然处于“已添加”状态,因此它会抛出主键违例。
所以我得到了创建相同机制的任务,这使得在EF中进行回滚。当抛出异常时,他们想要原始数据。正如您在上面的代码中看到的,现在没有类似的东西。当然,我在脑海中有交易,但是如何将它实现到您可以在上面看到的当前实现?
我的想法是从DB获取当前实体。在异常的情况下,我使用保存前获得的数据调用SaveMyEntity。但很少有问题:
我可以给你一些建议吗?
非常感谢!
编辑:
我刚发现TransactionScope的存在。所以我试着做这样的事情
void SaveMyEntity(MyEntity myEntity)
{
//...
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
{
using(var context = new SomeContext())
{
//...
if (myEntity.EntityB != null && myEntity.EntityB.Count > 0)
{
foreach (var u in myEntity.EntityB.ToList())
{
context.entity_b_context_base.Attach(u);
context.SyncObjectState(u, u.ObjectState);
}
context.SaveChanges();
}
if (myEntity.EntityC != null && myEntity.EntityC.Count > 0)
{
foreach (var t in myEntity.EntityC.ToList())
{
context.entity_c_context_base.Attach(t);
context.SyncObjectState(t, t.ObjectState);
}
context.SaveChanges();
}
// and so on ..
}
base.ExecuteStoredProcedure("validate_after_save", ref parameters, ref errorText);
if (!string.IsNullOrEmpty(errorText))
{
//Rollback
scope.Dispose();
throw new OwnException("Save failed: " + errorText);
}
else
{
//Commit
scope.Complete();
}
}
}
它确实很好用。但我不确定这是否是正确的解决方案。