一. 用法
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); } } }
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>(); } }
三. 原理代码剖析
详见:https://www.bilibili.com/read/cv8545714
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。