• 第二十一节:EFCore5.0基于【Zack.EFCore.Batch 】实现批量更新/删除、横向比较性能、剖析实现原理


    一. 用法

    1. 说明

     关于该程序集详细的介绍、背景、原理,直接去看老杨自己的文章。(支持:SQLServer、MySQL、Oracle、Postgresql、Sqlite,EFCore必须5.0以上)

    文章参考:https://www.bilibili.com/read/cv8545714   https://mp.weixin.qq.com/s/t0wd5B_N_IWhN61xw0CxXw

                    (关于用法,要参考GitHub中的最新写法!!!!!)

    GitHub:https://github.com/yangzhongke/Zack.EFCore.Batch

    总结:

      该程序集实现的批量更新、批量删除功能可以通过生成一条Update、Delete语句来实现,而不需要EFCore原始的写法先查询后操作了。

    2. 基于SQLServer

     首先要有4个基本的程序集,然后通过nuget安装程序集【Zack.EFCore.Batch.MSSQL 1.4.3】,然后在DBContext上下文中OnConfiguring添加代码 optionsBuilder.UseBatchEF_MSSQL();

     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     {
                optionsBuilder.UseLoggerFactory(LoggerFactory.Create(build =>
                {
                    build.AddDebug();
                }));
    
                optionsBuilder.UseBatchEF_MSSQL();// MSSQL Server 用户用这个
     }

    (1). 批量删除: DeleteRange 和 DeleteRangeAsync

    代码分享:

    {
       var count1 = dbContext.DeleteRange<T_UserInfor>(u => u.id == "1");
    }

    (2). 批量修改: BatchUpdate.Where().Execute() 和 .ExecuteAsync()

    代码分享:

                    {
                        var count2 = dbContext.BatchUpdate<T_UserInfor>()
                              .Where(u => u.userSex.Contains(""))
                              .Set(u => u.userAge, u => u.userAge + 100)
                              .Set(u => u.userName, u => "ypf001")
                              .Execute();
                    }

    PS:条件中支持关系对象(外键的模式)进行拼接

                {
                        var count2 = dbContext.BatchUpdate<T_UserInfor>()
                              .Where(u => u.UserRole.id="111")
                              .Set(u => u.userAge, u => u.userAge + 100)
                              .Set(u => u.userName, u => "ypf001")
                              .Execute();
                }

    (3). 支持Take()、Skip()来限制删除和更新数据的范围

     批量删除和批量更新都支持通过Take()、Skip()来实现部分删除和部分更新,例子代码如下:

     【1.4.3】中不好用

    (4). 批量插入

      BulkInsert()底层使用各个数据库的BulkCopy机制实现数据插入,因此插入效率非常高。目前有如下两个缺点:不支持关联数据的自动插入,对于关联的对象,请同样调用BulkInsert()进行插入;由于PostgreSQL的.NET Core Provider还没有支持BulkCopy,所以目前Zack.EFCore.Batch暂不支持PostgreSQL。

      【1.4.3】中不好用

    (5). 整合事务:可以集成到事务中

    代码分享:

      {
                        using (var transaction = dbContext.Database.BeginTransaction())
                        {
                            try
                            {
                                //业务1
                                T_UserInfor userInfor = new T_UserInfor()
                                {
                                    id = Guid.NewGuid().ToString("N"),
                                    userName = "ypf",
                                    userSex = "",
                                    userAge = 100,
                                    addTime = DateTime.Now
                                };
                                dbContext.Add(userInfor);
                                dbContext.SaveChanges();
    
                                //批量修改
                                var count2 = dbContext.BatchUpdate<T_UserInfor>()
                                     .Where(u => u.userSex.Contains(""))
                                     .Set(u => u.userAge, u => u.userAge + 100)
                                     .Set(u => u.userName, u => "ypf1234")
                                     .Execute();
    
                                //模拟错误
                                T_UserInfor userInfor2 = new T_UserInfor()
                                {
                                    id = Guid.NewGuid().ToString("N") + "fffff",        //模拟错误
                                    userName = "ypf1",
                                    userSex = "男1111",
                                    userAge = 111,
                                    addTime = DateTime.Now
                                };
                                dbContext.Add(userInfor2);
                                dbContext.SaveChanges();
    
                                //统一提交
                                transaction.Commit();
                            }
                            catch (Exception ex)
                            {
                                //using包裹不需要手写rollback
                                Console.WriteLine(ex.Message);
                            }
                        }
                    }
    View Code

    3. 基于MySQL

     首先要有4个基本的程序集,然后通过nuget安装程序集【Zack.EFCore.Batch.MySQL.Pomelo 1.3.0】,然后在DBContext上下文中OnConfiguring添加代码 optionsBuilder.UseBatchEF_MySQLPomelo();

      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
                optionsBuilder.UseLoggerFactory(LoggerFactory.Create(build =>
                {
                    build.AddDebug();
                }));
                optionsBuilder.UseBatchEF_MySQLPomelo();//as for MySQL
      }

    (1). 批量删除: DeleteRange 和 DeleteRangeAsync

    (2). 批量修改: BatchUpdate.Where.Set().Execute() 和 .ExecuteAsync()

    (3). 整合事务:可以集成到事务中

    代码写法同SQLServer 

    二. 横向比较性能

    1. 说明

     关于批量修改和批量删除,常用的程序集还有两个,【EFCore.BulkExtensions】【Z.EntityFramework.Plus.EFCore】,但是前者不支持MySQL。

    2. 测试结果

    3. 代码分享 

                {
                    using (EFDB01Context db = new EFDB01Context())
                    {
                        Stopwatch watch = new Stopwatch();
                        watch.Start();
    
    
                        #region 批量删除-EFCore.BulkExtensions
                        //{
                        //    int count1 = db.T_UserInfor.Where(u => u.userName == "1").BatchDelete();
                        //}
                        #endregion
    
                        #region 批量删除-Z.EntityFramework.Plus.EFCore
                        //{
                        //    int count1 = db.T_UserInfor.Where(u => u.userName == "1").Delete();
                        //}
                        #endregion
    
                        #region 批量删除-Zack.EFCore.Batch 
                        //{
                        //    int count1 = db.DeleteRange<T_UserInfor>(u => u.userName == "1");
                        //}
                        #endregion
    
                        #region 批量修改-EFCore.BulkExtensions(全赋新值)
                        //{
                        //    int count1 = db.T_UserInfor.Where(u => u.userName == "1").BatchUpdate(new T_UserInfor() { userSex = "女12354", userAge = 100, addTime = DateTime.Now });
                        //}
                        #endregion
    
    
                        #region 批量修改-Z.EntityFramework.Plus.EFCore(全赋新值)
                        //{
                        //    int count1 = db.T_UserInfor.Where(u => u.id != "1").Update(x => new T_UserInfor() { userSex = "女12354", userAge = 100, addTime = DateTime.Now });
                        //}
                        #endregion
    
                        #region 批量修改-Zack.EFCore.Batch(全赋新值) 
                        //{
                        //    int count1 = db.BatchUpdate<T_UserInfor>()
                        //        .Set(b => b.userSex, b => "女12354")
                        //        .Set(b => b.userAge, b => 100)
                        //        .Set(b => b.addTime, b => DateTime.Now)
                        //        .Execute();
                        //}
                        #endregion
    
    
                        #region 批量修改-Zack.EFCore.Batch(原值基础上修改-上面时间基本一致) 
                        //{
                        //    int count1 = db.BatchUpdate<T_UserInfor>()
                        //        .Set(b => b.userSex, b => b.userSex + "123")
                        //        .Set(b => b.userAge, b => b.userAge + 100)
                        //        .Set(b => b.addTime, b => DateTime.Now)
                        //        .Execute();
                        //}
                        #endregion
    
                        watch.Stop();
                        Console.WriteLine($"用时:{watch.ElapsedMilliseconds}");
    
                        //修改完删掉
                        //db.Truncate<T_UserInfor>();
    
                    }
                }
    View Code

    三. 原理代码剖析

     详见:https://www.bilibili.com/read/cv8545714

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    【javascript基础】【转】各浏览器对页面外部资源加载的策略
    【javascript基础】【转】javascript模块化、模块加载器初探
    【javascript基础】js线程机制【转】
    【css】【转】那些年我们一起清除过的浮动
    IL入门之旅(三)——Dump对象
    学习TPL(一)
    弱引用应用的注意点
    IL入门之旅(二)——动态包装
    学习TPL(二)
    IL之旅(前言)
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/14441115.html
Copyright © 2020-2023  润新知