using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.Serializable, Timeout = new TimeSpan(0, 10, 0) })) { using (var context = new SilviSIMSContext(SingletonBase<DataAccess>.Instance.ConnectionString)) { //Do something context.SaveChanges(); //Do something //此处循环大概3W多条数据, 添加到临时变量lst // 使用AddRange(lst); //没循环结束就报错 context.SaveChanges(); } }
报错:与当前连接相关联的事务已经完成,但尚未释放。必须先释放该事务,然后才能使用该连接来执行 SQL 语句。
是不是超时了?
是的
@yy_yang: 那你把时间加长,也会报错?
@Yu: 恩,试过,一样报错
@Yu: 但是去掉事务就不报错
@yy_yang: 你把 list的量控制一下, 试试还会不会报错 如 Task(10);
@Yu: 第一个SaveChanges 和第二个 SaveChanges 之间加个
Thread.Sleep(5000); 试试
@Yu:谢谢你的建议 ,还是循环那点报错
@yy_yang: 或在第一个SaveChanges之后加一个 context.Connection.Open()
@yy_yang:
在第一个SaveChanges之后加
if (context.Connection.State == System.Data.ConnectionState.Closed)
context.Connection.Open();
@Yu: 不得行哦,这state本来就是closed的
@Yu: public abstract ConnectionState State { get; }
@yy_yang: 你试把第一个savechanges 注释掉,应该就不会报错
@yy_yang: State 状态是会变化的
@Yu: open直接报错:服务器上的 MSDTC 不可用。
@Yu: 还是不行,接着报:分布式事务已完成。请将此会话登记到新事务或 NULL 事务中,试过http://www.cnblogs.com/chriskwok/archive/2012/05/12/2497203.html , 这错误一个接一个了
@yy_yang: 只有第二个savechanges 是不是就不会报错?
@Yu: 恩
@yy_yang: 那你开两个 context 吧
context1.SaveChanges
context2.SaveChanges
看到这样的代码,我也是醉了,这位同学在老师上课的时候一定很认真听讲。
一眼就看出来,标准的Using用法,老师都是这么跟我们说的。
不用Using不是中国人。
咳咳,老师好!
@yy_yang: 奇怪,我没有办法插入链接了,按钮是灰的。
How to: Manage Transactions in the Entity Framework
http://msdn.microsoft.com/en-us/library/vstudio/bb738523(v=vs.100).aspx
@爱编程的大叔: 请教下,上面代码中写法有什么问题吗?
事务超时,要么弄成20分钟试试,或者只处理10条而不是3w条试试
@arg: 少量数据没问题
@yy_yang: 你这种事情,要什么事务?事务不要钱是吧?
另外,就算不用事务,一般也不这样保存数据的。
要么一条条SaveChanges,要么大约弄个50条,100条左右的Save一次。
多了肯定出问题。
@爱编程的大叔: 这里没办法,必须要用到事务,因为需要导入另外一个数据库的数据,第一个savechanges处,需要把参数存入到数据库中,然后把这个参数传入到客户定义的存储过程中,不这样弄没办法做
@yy_yang: 你的意思是在For循环中出错了?你为什么不贴FOR的代码?
我的意思是,你的事务什么时候Commit?
@爱编程的大叔: 事务是在第二个SaveChanges()后Commit的,我说的for里面出错,是我在调试的时候每次都是for没执行完就报错
var lstInventorySS = new List<InventoryStandStock>(); foreach (var stock in inventoryStocks) { if (!dicInventory.ContainsKey(stock.CutblockSequenceNumber.Value)) continue; var specy = lstSpecies.FirstOrDefault(s => s.Code.Equals(stock.SpeciesId.ToString(), StringComparison.OrdinalIgnoreCase)); var tree_class = lstTreeClass.FirstOrDefault(t => t.Code.Equals(stock.TreeClassId)); int productSpecificationId = 1; var defectType = lstDefectTypes.FirstOrDefault(d => d.Code.Equals(stock.DefectTypeId.Value.ToString(), StringComparison.OrdinalIgnoreCase)); if (specy.SpeciesGroups.Count > 0) { var groupId = specy.SpeciesGroups.First().Id; var product = lstProduct.FirstOrDefault(p => p.ProductType.Code.Equals(stock.ProductTypeId) && p.IsInventoryProduct && p.ProductType.SpeciesGroupId == groupId); if (product != null) { productSpecificationId = ProductDAL.Instance.GetInventoryProSpecId(product.Id); } } var inventoryStock = new InventoryStandStock { Id = ++inventoryStockId, InventoryId = dicInventory[stock.CutblockSequenceNumber.Value], SpeciesId = specy.Id, TreeClassId = tree_class == null ? (byte)1 : tree_class.Id, ProductSpecificationId = productSpecificationId, DefectTypeId = defectType == null ? (byte)1 : defectType.Id, DiameterBreastHeight = stock.DiameterBreastHeight, TreesPerArea = stock.TreesPerAcre, MerchantableTreeHeight = stock.MerchantableTreeHeight, TotalTreeHeight = stock.TotalTreeHeight, YieldWeight = stock.GreenTons, GrossYieldBoardFeet = stock.GrossBoardFeet, PercentDefect = null, YieldCubic = null }; lstInventorySS.Add(inventoryStock); //context.InventoryStandStocks.Add(inventoryStock); //context.Entry(inventoryStock).State = EntityState.Added; }
@yy_yang: 这个我就完全不能理解了,有什么事情是需要执行3万多条数据,还得保持事务的。
我的意思是你能不能简化事务?
@爱编程的大叔: 这样说吧,客户给的存储过程中有个参数SessionId ,而当前应用数据库中有个session表 ,首先第一个savechanges是保存的session(sessionId对应多个老数据库中的ID),接着通过这个sessionId去调用客户的存储过程取数据,进而保存到当前应用的数据库中
@yy_yang: 这跟事务有什么关系?
@yy_yang: db1(旧数据) ,db2(现数据 session(sessionid,id));
查询类似:select * from db1.table1 t1 inner join db2.table2 t2 on t1.id =t2.id where t2.sessionId= sessionId
@yy_yang: 我需要提前存入session表的记录,如果后面保存数据失败就回滚
@yy_yang: 3万条没有办法分成30条30条commit?那你的意思就是这3万条非得同时成功,同时失败?
我还是完全无法想象。
分批, 一次不要这么多。 你还能加上进度条