使用实体框架的外部System.Common.DBTransaction
本文关键字:System Common DBTransaction 外部 实体 框架 | 更新日期: 2023-09-27 17:52:45
我被困在一个问题,将发生在ADO的每个人。. NET与实体框架上下文混合。我有一个大的过程,处理和保存数据到数据库中使用多种方式,如ADO。. NET数据适配器和针对DB的直接CRUD命令。所有的过程都被2个using()块包装起来,这些块创建和释放一个DBConnection/DBTransaction和一个try/catch块来提交或回滚事务。不幸的是,在这个例程的中间,我不得不回忆使用实体框架实现的保存过程。这给我带来了一个问题:
根据官方文档,实体框架5允许我通过与事务相关的事务的连接(它应该工作,在调试模式下,当我调用SaveChanges()时,我没有收到任何TimeOutException由于死锁,相反,如果我通过一个新的连接,它确实),但不幸的是,SaveChanges()在连接被关闭后,关联的事务提交!即使我设置了标志'contextOwnsConnection'!
据我所知,如果我迁移EF5到EF6,事情应该工作(我是对的吗?),但不幸的是我不能,因为我正在做的项目是非常大的,涉及到很多依赖关系,这将需要大量的时间。
我怎么能使它与EF5工作?有什么技巧或模式可以达到预期的结果吗?关于EF6的行为我是对的吗?它值得迁移到EF6吗?
这是一个简单的例子,说明我的代码看起来是什么样的。出于隐私原因,我不能发布原始代码,但想象一下这样的情况,有更多的复杂性:
using(DbConnection conn = DBProvider.CreateConnection()){
//Open the created connection
conn.Open();
//Create a new transaction
using(DbTransaction tr = DBProvider.CreateTransaction()){
//Begin a new transaction
tr.Begin();
bool saveOk;
try{
//Updates customers by using dataadapter
dataAdapterCustomers.InsertCommand.Transaction = tr;
dataAdapterCustomers.UpdateCommand.Transaction = tr;
dataAdapterCustomers.DeleteCommand.Transaction = tr;
dataAdapterCustomers.Update();
//Updates stock items by using dataadapter
stockAdapterCustomers.InsertCommand.Transaction = tr;
stockAdapterCustomers.UpdateCommand.Transaction = tr;
stockAdapterCustomers.DeleteCommand.Transaction = tr;
stockAdapterCustomers.Update();
//...Many other DB accessing here...
//Updates stock quantity by using simple DBCommand
quantityUpdateCmd.Transaction = tr;
quantityUpdateCmd.ExecuteNonQuery();
//Updates stock statistics by using a simple DBCommand
updateStockStatsCmd.Transaction = tr;
updateStockStatsCmd.ExecuteNonQuery();
//...Many other DB accessing here...
//HERE:
//Creates a new activity and save it using EF.
//I use a UnitOfWork and i pass to it my connection and 'false' as contextOwnsConnection parameter
//(it 'll be used by the DBContext contained in my Unit of work)
using(ActivityUoW uow = new ActivityUoW(conn, false)){
Activity act = new Activity();
act.Name = "Saving activity";
act.Description = "Done by user";
act.Date = DateTime.Now;
uow.Activities.Add(act);
uow.SaveChanges();
}
//Based on activity result, launch a store procedure that makes other complex things.
UNFORTUNATELY THE CONNECTION HAS BEEN CLOSED AND TRANSACTION COMMITTED, SO THE FOLLOWING INSTRUCTION WILL FAIL.
launchActivityUpdateSpCmd.Transaction = tr;
launchActivityUpdateSpCmd.ExecuteNonQuery();
//...Many other DB accessing here...
//Data saved correctly
saveOk = true;
}
catch(Exception ex){
//There was an error during save
saveOk = false;
}
//Commit or rollback transaction according to save procedure result
if(saveOk)
tr.Commit();
else
tr.Rollback();
}
}
我不太明白你的问题,也不确定你的问题是否与如何处理事务有关,或者你是否对EF5到EF6迁移有疑问。话虽如此,你有一个有趣的混合数据访问代码。
关于事务——我会考虑使用TransactionScope,它是系统的一部分。交易名称空间。
例如: try
{
using (var scope = new TransactionScope())
{
using (var conn = new SqlConnection("your connection string"))
{
conn.Open();
// your EF and ADO.NET code
}
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
}
catch (ApplicationException ex)
{
}