zoukankan      html  css  js  c++  java
  • EF中关于TransactionScope的使用

    前提条件

     

    TransactionScope类需要引用System.Transactions;

    数据库环境及需求

    现在假设有两个表如图:

                                          

               表TA                                                                                  表TB 

    现有数据:                                            

     现在的需求是:每往TA中插入一条数据,就更新TB的第一行,值为表TA的所有行的Age的平均值

     可以看到表TB的Remark长度仅仅为2,待会利用这个制造错误

     

    当不使用TransactionScope时:

     using (EFTestEntities db = new EFTestEntities())
                {
                    //数据库TA原有2行,此时添加第3行
                    var aEntity = new TA
                    {
                        Name = "a",
                        Age = 20
                    };
                    db.TA.Add(aEntity);
    
                    var listTA = db.TA.ToList();//此时list只有2行,新添加的没有读取到
                    int totalAge = 0;
                    listTA.ForEach(p => totalAge += p.Age);
    
                    //获取表TB的第一行,并修改AvgAge值
                    var bEntity = db.TB.First();
                    bEntity.AvgAge = totalAge / listTA.Count;
                    bEntity.Remark = "bb";
                    db.SaveChanges();
                    //结果是Tb的值没有变化
                }  
    View Code

    你认为是添加TA后没有db.SaveChanges();? 的确,添加这个之后,可以读取到新添加的值了,但是没有事务了,如:

    using (EFTestEntities db = new EFTestEntities())
                {
                    //数据库TA原有2行,此时添加第3行
                    var aEntity = new TA
                    {
                        Name = "a",
                        Age = 20
                    };
                    db.TA.Add(aEntity);
                    db.SaveChanges();
    
                    var listTA = db.TA.ToList();//此时list有3行了,新添加的可以被读取到
                    int totalAge = 0;
                    listTA.ForEach(p => totalAge += p.Age);
    
                    //获取表TB的第一行,并修改AvgAge值
                    var bEntity = db.TB.First();
                    bEntity.AvgAge = totalAge / listTA.Count;
                    bEntity.Remark = "bbc";//故意超出长度,制造错误
                    db.SaveChanges();
                    //结果是TA添加了新行,但是TB修改时出错导致修改失败。造成了数据不一致
                }  
    View Code

    结果是TA添加了新行,但是TB因为remark超出长度导致导致修改失败,此时TB的数据是错的。

    怎样可以避免这个问题?答案就是用事务。

    使用TransactionScope:

    using (EFTestEntities db = new EFTestEntities())
                {
                    using (TransactionScope ts = new TransactionScope())
                    {
                        //数据库TA原有2行,此时添加第3行
                        var aEntity = new TA
                        {
                            Name = "a",
                            Age = 20
                        };
                        db.TA.Add(aEntity);
                        db.SaveChanges();//重点,必须要db.SaveChanges(),然后下面才能获取到新添加的行
    
                        var listTA = db.TA.ToList();//此时list有3行了,新添加的可以被读取到
                        int totalAge = 0;
                        listTA.ForEach(p => totalAge += p.Age);
    
                        //获取表TB的第一行,并修改AvgAge值
                        var bEntity = db.TB.First();
                        bEntity.AvgAge = totalAge / listTA.Count;
                        bEntity.Remark = "bbc";//故意超出长度,制造错误
                        db.SaveChanges(); //执行到此处程序报错
    
                        ts.Complete();//事务提交未执行
                        //结果是自动回滚,相当于此次没有对数据库做任何操作。保持了数据一致性
                    }
                }
    View Code

     下面给出正确的示例,实现以上需求:

    using (EFTestEntities db = new EFTestEntities())
                {
                    using (TransactionScope ts = new TransactionScope())
                    {
                        //数据库TA原有2行,此时添加第3行
                        var aEntity = new TA
                        {
                            Name = "a",
                            Age = 20
                        };
                        db.TA.Add(aEntity);
                        db.SaveChanges();//重点,必须要db.SaveChanges(),然后下面才能获取到新添加的行
    
                        var listTA = db.TA.ToList();//此时list有3行了,新添加的可以被读取到
                        int totalAge = 0;
                        listTA.ForEach(p => totalAge += p.Age);
    
                        //获取表TB的第一行,并修改AvgAge值
                        var bEntity = db.TB.First();
                        bEntity.AvgAge = totalAge / listTA.Count;
                        bEntity.Remark = "bb";//数据符合规范
                        db.SaveChanges(); //保存
    
                        ts.Complete();//提交事务
                        //结果是执行成功,TA多一条数据,同时TB的值也变了
                    }
                }
    View Code

    一切都nice了!

  • 相关阅读:
    Android游戏开发22:Android动画的实现J2me游戏类库用于Android开发
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第三部分,完整代码)
    使用OGR创建dxf格式矢量数据
    mysql 数据库引擎 MyISAM InnoDB 大比拼 区别
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第二部分)
    mysql 更改数据库引擎
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第一部分)
    android 数字键盘使用
    MySQL Innodb数据库性能实践
    eclipse : Error while performing database login with the driver null
  • 原文地址:https://www.cnblogs.com/dengshaojun/p/5761013.html
Copyright © 2011-2022 走看看