首页 新闻 会员 周边

TransactionScope ,ef批量添加数据报错

1
悬赏园豆:50 [已解决问题] 解决于 2014-12-08 10:04
 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 语句。

阳.咩咩的主页 阳.咩咩 | 初学一级 | 园豆:4
提问于:2014-12-05 12:36
< >
分享
最佳答案
0

是不是超时了?

收获园豆:30
Yu | 专家六级 |园豆:12980 | 2014-12-05 13:05

是的

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:06

@yy_yang: 那你把时间加长,也会报错?

Yu | 园豆:12980 (专家六级) | 2014-12-05 13:07

@Yu: 恩,试过,一样报错

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:10

@Yu: 但是去掉事务就不报错

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:10

@yy_yang: 你把 list的量控制一下, 试试还会不会报错 如 Task(10);

Yu | 园豆:12980 (专家六级) | 2014-12-05 13:13

@Yu: 第一个SaveChanges 和第二个 SaveChanges 之间加个

Thread.Sleep(5000); 试试

Yu | 园豆:12980 (专家六级) | 2014-12-05 13:26

@Yu:谢谢你的建议 ,还是循环那点报错

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:38

@yy_yang: 或在第一个SaveChanges之后加一个 context.Connection.Open()

Yu | 园豆:12980 (专家六级) | 2014-12-05 13:38

@yy_yang: 

在第一个SaveChanges之后加

if (context.Connection.State == System.Data.ConnectionState.Closed)
context.Connection.Open();

Yu | 园豆:12980 (专家六级) | 2014-12-05 13:41

@Yu: 不得行哦,这state本来就是closed的

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 14:01

@Yu: public abstract ConnectionState State { get; }

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 14:04

@yy_yang: 你试把第一个savechanges 注释掉,应该就不会报错

Yu | 园豆:12980 (专家六级) | 2014-12-05 14:06

@yy_yang: State 状态是会变化的

Yu | 园豆:12980 (专家六级) | 2014-12-05 14:07

@Yu: open直接报错:服务器上的 MSDTC 不可用。

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 14:17
Yu | 园豆:12980 (专家六级) | 2014-12-05 14:19
阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 15:07

@yy_yang: 只有第二个savechanges 是不是就不会报错?

Yu | 园豆:12980 (专家六级) | 2014-12-05 15:17

@Yu: 恩

阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 15:28

@yy_yang: 那你开两个 context 吧

 

context1.SaveChanges

context2.SaveChanges

Yu | 园豆:12980 (专家六级) | 2014-12-05 15:33
其他回答(2)
0

看到这样的代码,我也是醉了,这位同学在老师上课的时候一定很认真听讲。

一眼就看出来,标准的Using用法,老师都是这么跟我们说的。

不用Using不是中国人。

收获园豆:20
爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 12:44

咳咳,老师好!

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 12:45

@yy_yang: 奇怪,我没有办法插入链接了,按钮是灰的。

How to: Manage Transactions in the Entity Framework

http://msdn.microsoft.com/en-us/library/vstudio/bb738523(v=vs.100).aspx

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 12:50

@爱编程的大叔: 请教下,上面代码中写法有什么问题吗?

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:03

事务超时,要么弄成20分钟试试,或者只处理10条而不是3w条试试

支持(0) 反对(0) arg | 园豆:1047 (小虾三级) | 2014-12-05 13:11

@arg: 少量数据没问题

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:12

@yy_yang: 你这种事情,要什么事务?事务不要钱是吧?

另外,就算不用事务,一般也不这样保存数据的。

要么一条条SaveChanges,要么大约弄个50条,100条左右的Save一次。

多了肯定出问题。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 13:16

@爱编程的大叔: 这里没办法,必须要用到事务,因为需要导入另外一个数据库的数据,第一个savechanges处,需要把参数存入到数据库中,然后把这个参数传入到客户定义的存储过程中,不这样弄没办法做

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 13:24

@yy_yang: 你的意思是在For循环中出错了?你为什么不贴FOR的代码?

我的意思是,你的事务什么时候Commit?

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 14:29

@爱编程的大叔: 事务是在第二个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;
                }
支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 14:43

@yy_yang: 这个我就完全不能理解了,有什么事情是需要执行3万多条数据,还得保持事务的。

我的意思是你能不能简化事务?

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 14:49

@爱编程的大叔: 这样说吧,客户给的存储过程中有个参数SessionId ,而当前应用数据库中有个session表 ,首先第一个savechanges是保存的session(sessionId对应多个老数据库中的ID),接着通过这个sessionId去调用客户的存储过程取数据,进而保存到当前应用的数据库中

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 14:55

@yy_yang: 这跟事务有什么关系?

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 14:58

@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

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 15:00

@yy_yang: 我需要提前存入session表的记录,如果后面保存数据失败就回滚

支持(0) 反对(0) 阳.咩咩 | 园豆:4 (初学一级) | 2014-12-05 15:01

@yy_yang: 3万条没有办法分成30条30条commit?那你的意思就是这3万条非得同时成功,同时失败?

我还是完全无法想象。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-12-05 15:25
0

分批, 一次不要这么多。 你还能加上进度条

问天何必 | 园豆:3311 (老鸟四级) | 2014-12-05 13:55
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册