9.10 批量操作
9.10.1 关于批量操作
Furion
框架中,默认只提供小数据(100 条 以内)批量数据操作,如果需要更大的数据批量处理,推荐使用第三方包 Zack.EFCore.Batch,支持和 Furion
无缝衔接。
9.10.2 Zack.EFCore.Batch
使用
EFCore
拦截器说明使用该第三方拓展库可能不会触发 EFCore
的拦截器,如 DbCommandInterceptor
,SaveChangesInterceptor
。
9.10.2.1 安装对应的数据库 NuGet
包
MSSQL
:Zack.EFCore.Batch.MSSQL
MySql
:Zack.EFCore.Batch.MySQL.Pomelo
Npgsql
:Zack.EFCore.Batch.Npgsql
Oracle
:Zack.EFCore.Batch.Oracle
Sqlite
:Zack.EFCore.Batch.Sqlite
9.10.2.2 注册并配置服务
services.AddDatabaseAccessor(options =>
{
options.AddDbPool<DefaultDbContext>(providerName: default, optionBuilder: (services, opt) => // 如果是 v3.7.11 之前,使用 opt =>
{
opt.UseBatchEF_Sqlite(); // SQlite 数据库包
});
});
9.10.2.3 基本使用
// 批量更新
await repository.Context.BatchUpdate<Book>()
.Set(b => b.Price, b => b.Price + 3)
.Set(b => b.Title, b => s)
.Set(b => b.AuthorName,b=>b.Title.Substring(3,2)+b.AuthorName.ToUpper())
.Set(b => b.PubTime, b => DateTime.Now)
.Where(b => b.Id > n || b.AuthorName.StartsWith("Zack"))
.ExecuteAsync();
// 批量删除
await repository.Context.DeleteRangeAsync<Book>(b => b.Price > n || b.AuthorName == "zack yang");
9.10.3 EFCore.BulkExtensions
使用
通过 NuGet
安装 EFCore.BulkExtensions
包即可。
9.10.3.1 常见批量操作
// 批量插入
repository.Context.BulkInsert(entitiesList);
repository.Context.BulkInsertAsync(entitiesList);
// 批量更新
repository.Context.BulkUpdate(entitiesList);
repository.Context.BulkUpdateAsync(entitiesList);
// 批量删除
repository.Context.BulkDelete(entitiesList);
repository.Context.BulkDeleteAsync(entitiesList);
// 批量插入或更新
repository.Context.BulkInsertOrUpdate(entitiesList);
repository.Context.BulkInsertOrUpdateAsync(entitiesList);
// 批量插入或更新或删除
repository.Context.BulkInsertOrUpdateOrDelete(entitiesList);
repository.Context.BulkInsertOrUpdateOrDeleteAsync(entitiesList);
// 批量读取多个实体
repository.Context.BulkRead(entitiesList);
repository.Context.BulkReadAsync(entitiesList);
// 批量清空表(慎用!!!!!)
repository.Context.Truncate<Entity>();
repository.Context.TruncateAsync<Entity>();
9.10.3.2 查询后批量操作
// 根据条件批量删除
repository.Where(a => a.ItemId > 500).BatchDelete();
await repository.Where(a => a.ItemId > 500).BatchDeleteAsync();
// 根据条件批量更新
repository.Where(a => a.ItemId <= 500).BatchUpdate(a => new Item { Quantity = a.Quantity + 100 });
repository.Where(a => a.ItemId <= 500).BatchUpdate(new Item { Description = "Updated" });
await repository.Where(a => a.ItemId <= 500).BatchUpdateAsync(new Item { Description = "Updated" });
// 批量更新指定列
var updateColumns = new List<string> { nameof(Item.Quantity) };
var q = repository.Where(a => a.ItemId <= 500);
int affected = q.BatchUpdate(new Item { Description = "Updated" }, updateColumns);
9.10.3.3 批量操作性能
Operations\Rows | 100,000 EF | 100,000 EFBulk | 1,000,000 EFBulk |
---|---|---|---|
Insert | 38.98 s | 2.10 s | 17.99 s |
Update | 109.25 s | 3.96 s | 31.45 s |
Delete | 7.26 s | 2.04 s | 12.18 s |
----------------- | ------------ | ---------------- | ------------------ |
Together | 70.70 s | 5.88 s | 56.84 s |
9.10.4 EFCore 7
内置批量操作
非微软支持数据库适配问题
如果使用的是非微软支持的数据库,如 Oracle
,MySQL
,PostgreSQL
等,可能适配 EFCore 7
不及时会出现找不到方法异常。
// 批量删除
await repository.Entities.ExecuteDeleteAsync();
await repository.Entities.Where(t => t.Text.Contains(".NET")).ExecuteDeleteAsync();
await repository.Entities.Where(t => t.Posts.All(e => e.PublishedOn.Year < 2022)).ExecuteDeleteAsync();
// 批量更新
await repository.Entities.ExecuteUpdateAsync(
s => s.SetProperty(b => b.Name, b => b.Name + " *Featured!*"));
await repository.Entities
.Where(p => p.PublishedOn.Year < 2022)
.ExecuteUpdateAsync(s => s
.SetProperty(b => b.Title, b => b.Title + " (" + b.PublishedOn.Year + ")")
.SetProperty(b => b.Content, b => b.Content + " ( This content was published in " + b.PublishedOn.Year + ")"));
await repository.Entities
.Where(t => t.Posts.All(e => e.PublishedOn.Year < 2022))
.ExecuteUpdateAsync(s => s.SetProperty(t => t.Text, t => t.Text + " (old)"));
9.10.5 反馈与建议
与我们交流
给 Furion 提 Issue。
了解更多
想了解更多 EFCore.BulkExtensions
知识可查阅 EFCore.BulkExtensions 开源仓库。