一、视频来源
Part3-36:EFCore如何批量删除、新增、修改、插入_哔哩哔哩_bilibili
二、概述
1、在EF Core7之前不支持高效的删除、新增、修改、插入数据,都是逐条操作。
2、理想的状态是和数据库一样支持批量操作以提高性能:Delete from Movie where Price>33
3、在EF Core7之前,RemoveRange、AddRange底层依然是逐条操作,例如对于查询出来的多条数据做RemoveRange操作查看生成的SQL语句,每条数据都生成一个对应的DELETE SQL语句,依然是对每条数据进行一次DELETE的操作RemoveRange等同于循环操作Remove,二者并无本质区别,均是逐条操作。
public static void Main(string[] args)
{
MyDdContext db = new MyDdContext();
var articles = db.Articles.Where(a => a.Title.Contains("乌克兰"));
db.Articles.RemoveRange(articles);
db.SaveChanges();
}
4、在EF Core7新增 ExecuteDelete 和 ExecuteUpdate 用于进行批量删除和更新操作。但是依然无法批量新增数据。
三、为什么不使用原生SQL实现高效的删除、新增、修改、插入数据
1、原生SQL语句需要把表名、列名等硬编码到SQL语句中,不符合模型驱动、分层隔离等思想;程序员直接面对数据库表,无法利用EF Core强类型的特性;如果模型发生改变,必须手动变更SQL语句。
2、无法利用EF Core强大的SQL翻译机制来屏蔽不同底层数据库的差异。
3、EF Core官方迟迟未支持【批量高效的删除、新增、修改、插入数据】的原因:批量操作了某个条件的数据后,这个批量操作之前查询的数据EF Core无法知道怎么去做处理了,进入一种混乱状态。
4、相关问题讨论:ExecuteUpdate/Delete (AKA bulk update, without loading data into memory) · Issue #795 · dotnet/efcore (github.com)
四、EF CORE 7 中的新功能:使用 ExecuteDelete 和 ExecuteUpdate 进行批量操作
1、以ExecuteDelete 为例:可以看到生成的SQL语句是DELETE + WHERE的批量操作。
public static void Main(string[] args)
{
MyDdContext db = new MyDdContext();
var articles = db.Articles.Where(a => a.Title.Contains("乌克兰"));
articles.ExecuteDelete();
db.SaveChanges();
}
五、EF CORE6及以前使用开源包实现批量操作:Batch(作者:杨中科老师)
1、Nuget
- SQL SERVER数据库:NuGet\Install-Package Zack.EFCore.Batch.MSSQL
- MySQL数据库:NuGet\Install-Package Zack.EFCore.Batch.MySQL.Pomelo
- 其它数据库同理,在Nuget中搜索Zack.EFCore.Batch.数据库。
2、官方文档:包括其它的一些配置操作具体一定要参考文档,本文并不全面;内含详细的使用样例说明。
Zack.EFCore.Batch/README_CN.md at main · yangzhongke/Zack.EFCore.Batch (github.com)
3、对比EF Core官方提供的功能,可以批量导入(INSERT INTO)数据。
MyDdContext db = new MyDdContext();
db.DeleteRange<Article>(a => a.Title.Contains("广州") && a.Id<1000);
//var m = db.BatchUpdate<Article>()
//.Set(b => b.Message, b => "默哀")
//.Where(a => a.Title.Contains("广州") && a.Id < 1000)
//.Execute();
4、注意:如果项目中,既要连接Mysql,又要连接Sql Server,在调用BulkInsert()的时候可能会出现二义冲突,需要明确指定是哪个包,如下图所示,如果操作的是Mysql。这里涉及到的知识是C#的扩展方法二义冲突。