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了!

  • 相关阅读:
    Python机器学习笔记:使用sklearn做特征工程和数据挖掘
    Python numpy中矩阵的用法总结
    Python机器学习笔记:K-近邻(KNN)算法
    Python机器学习笔记:Logistic Regression
    python机器学习笔记:ID3决策树算法实战
    Mysql 多表查询详解
    JavaScript cookie操作实现点赞功能
    js操作cookie
    【IntelliJ IDEA】idea上提交代码到GitHub,已经提交了 但是GitHub上却没有的解决办法
    Mybatis分页插件PageHelper的配置和使用方法
  • 原文地址:https://www.cnblogs.com/dengshaojun/p/5761013.html
Copyright © 2011-2022 走看看