我对同事编写的代码有一个非常难看的问题。行动在TransactionScope
之内。首先执行数据库插入:
var billingRecord = new Billing
{
ACCOUNT_ID = AccountId,
AMOUNT = Amount,
};
_ObjectContext.AddToBilling(billingRecord);
_ObjectContext.SaveChanges(SaveOptions.None)
然后执行Web服务调用:
var webServiceCallResult = Request(params);
if (webServiceCallResult.Result == 1)
{
success = true;
}
else
{
success = false;
}
如果Web服务调用正常,则事务在finally块中完成:
finally
{
if (success)
{
tran.Complete();
_ObjectContext.AcceptAllChanges();
_Logger.Info(String.Format("Transaction completed"));
}
else
{
_Logger.Info(String.Format("Transaction uncompleted"));
}
}
问题是由于某种原因,某些记录未存储在数据库中。我测试了很多交易但在开发环境中从未发生过,但有时会发生在生产环境中。当我说"有时"这是因为这种情况很不寻常或很少见。
查看日志文件,我可以看到消息:
交易完成
并且没有显示异常,因此Web服务调用良好且事务已完成但记录未插入表。
我知道创建TransactionScope
没有必要,因为只有一个插入,不需要额外的数据库操作。 EF的对象上下文就像类中的全局var一样被创建并且永远不会丢弃,这是一种不好的做法,但据我所知,ObjectContext
将被垃圾收集器销毁,所以我认为是不是导致问题的原因。
我阅读了很多关于事务和使用实体框架ObjectContext
以及方法SaveChanges()
和AcceptAllChanges()
的正确方法,甚至代码都没有使用应该运行的最佳实践。我不想只重构代码,我想知道问题的真正原因。
感谢您的帮助。
我正在使用:
以下是完整的课程:
public class Implementation : IExecute
{
private readonly Logger _Logger;
private readonly ExampleEntities _ObjectContext = new ExampleEntities();
public TopUpExecuteImplementation()
{
_Logger = LogManager.GetLogger("Logger");
}
public Response perfomOperation(String account, String amount)
{
var success = false;
using (var tran = new System.Transactions.TransactionScope())
{
try
{
var accountRecord =
_ObjectContext.Accounts.First(
p => p.Account.Equals(account, StringComparison.InvariantCultureIgnoreCase));
var billingRecord = new Billing
{
ACCOUNT = account,
AMOUNT = amount,
};
_ObjectContext.AddToBillings(billingRecord);
_ObjectContext.SaveChanges(SaveOptions.None);
var webServiceCallResult = Request(account,amount);
_Logger.Info(String.Format("Request Result {0} ", webServiceCallResult.Result));
if (webServiceCallResult.Result == 0)
{
success = false;
}
else
{
if ((String.IsNullOrEmpty(webServiceCallResult.statusCode) == false) &&
(webServiceCallResult.statusCode.Equals("Success",
StringComparison.InvariantCultureIgnoreCase)))
{
success = true;
}
else
{
success = false;
}
}
}
catch (OptimisticConcurrencyException ex)
{
_Logger.Info(String.Format("Exception type {0} Exception {1} Inner Exception {2} ",
ex.GetType().ToString(), ex.Message,
ex.InnerException != null ? ex.InnerException.Message : String.Empty));
_ObjectContext.SaveChanges();
success = true;
}
catch (Exception e)
{
_Logger.Info(String.Format("Exception type {0} Exception {1} Inner Exception {2} ",
e.GetType().ToString(), e.Message,
e.InnerException != null ? e.InnerException.Message : String.Empty));
success = false;
}
finally
{
if (success)
{
tran.Complete();
_ObjectContext.AcceptAllChanges();
_Logger.Info(String.Format("Transaction completed"));
}
else
_Logger.Info(String.Format("Transaction uncompleted"));
}
}
return returnValue;
}
}