EFcore使用EFCore.BulkExtensions 批量增加、删除、修改

发布于:
分类: Python

EFCore.BulkExtensions 简介

  • EntityFrameworkCore扩展:批量操作(插入,更新,删除,读取,更新,同步)和批处理(删除,更新)。
  • 库是轻量级的,并且非常高效,具有所有最常用的CRUD操作。
  • 在Microsoft推荐的EFcore扩展 Top 20。
  • 当前版本使用的是EF Core 3.1,目前支持Microsoft SQL Server(2008+)和SQLite。
  • 它针对NetStandard 2.0,因此可以用于针对NetCore(2.0+)或NetFramework(4.6.1+)的项目。
  • 3.1.0和3.0.0之间的版本使用的是EF Core 3.0,并且以NetStandard 2.1为目标,因此只能在NetCore(3.0+)上使用。
  • 3.0之前的版本(最后2.6.4)针对NetStandard 2.0,可以与NetCore(2.2)或NetFramework(4.6.1+)一起使用。
  • EFCore / v.Nuget:EFCore2.1 / v2.4.1 EFCore2.0 / v2.0.8,对于EF Core 1.x,请使用1.1.0(以NetStandard 1.4为目标)
  • 请使用SqlBulkCopy进行插入,更新/删除合并具有原始Sql的 MERGE BulkInsert 。
  • 对于SQLite,没有BulkCopy,而是库将普通SQL与UPSERT结合使用。
  • 批量测试不能具有UseInMemoryDb,因为InMemoryProvider不支持特定于关系的方法。

在新版nuget上,用软件包管理器控制台命令安装:

Install-Package EFCore.BulkExtensions

用法

用法非常简单明了。

批量扩展是在DbContext类上进行的,可以像这样使用(支持常规和异步方法):

context.BulkInsert(entitiesList);                 context.BulkInsertAsync(entitiesList);
context.BulkUpdate(entitiesList);                 context.BulkUpdateAsync(entitiesList);
context.BulkDelete(entitiesList);                 context.BulkDeleteAsync(entitiesList);
context.BulkInsertOrUpdate(entitiesList);         context.BulkInsertOrUpdateAsync(entitiesList);       //Upsert
context.BulkInsertOrUpdateOrDelete(entitiesList); context.BulkInsertOrUpdateOrDeleteAsync(entitiesList); //Sync
context.BulkRead(entitiesList);                   context.BulkReadAsync(entitiesList);
context.Truncate<Entity>();                       context.TruncateAsync<Entity>();

批处理扩展是在IQueryable DbSet上进行的,可以在以下代码段中使用。

它们以纯sql的形式完成,并且不检查某些对象是否已预先装入内存并被跟踪。(updateColumns是可选参数,其中的PropertyNames在我们需要更新为其默认值时明确添加)

// Delete
context.Items.Where(a => a.ItemId >  500).BatchDelete();
context.Items.Where(a => a.ItemId >  500).BatchDeleteAsync();

// Update (using Expression arg.) supports Increment/Decrement 
context.Items.Where(a => a.ItemId <= 500).BatchUpdate(a => new Item { Quantity = a.Quantity + 100 });
  // can be as value '+100' or as variable '+incrementStep' (int incrementStep = 100;)
  
// Update (via simple object)
context.Items.Where(a => a.ItemId <= 500).BatchUpdate(new Item { Description = "Updated" });
context.Items.Where(a => a.ItemId <= 500).BatchUpdateAsync(new Item { Description = "Updated" });
// Update (via simple object) - requires additional Argument for setting to Property default value
var updateColumns = new List<string> { nameof(Item.Quantity) }; // Update 'Quantity' to default value('0'-zero)
var q = context.Items.Where(a => a.ItemId <= 500);
int affected = q.BatchUpdate(new Item { Description = "Updated" }, updateColumns);//result assigned to variable

批量操作

直接使用这些操作时,每个操作都是独立的事务,并且会自动提交。

如果我们需要在单个过程中执行多个操作,则应使用显式事务,例如:

using (var transaction = context.Database.BeginTransaction())
{
    context.BulkInsert(entitiesList);
    context.BulkInsert(subEntitiesList);
    transaction.Commit();
}

对于SQLite,BulkConfig中还有其他属性:{SqliteConnection,SqliteTransaction}通过以下方式使用显式事务:

using (var connection = (SqliteConnection)context.Database.GetDbConnection())
{
    connection.Open();
    using (var transaction = connection.BeginTransaction())
    {
        var bulkConfig = new BulkConfig() { SqliteConnection = connection, SqliteTransaction = transaction };
        context.BulkInsert(entities, bulkConfig);
        context.BulkInsert(subEntities, bulkConfig);
        transaction.Commit();
    }
}

 

当需要进行两项操作但与数据库建立一个连接时,可以使用BulkInsertOrUpdate方法。

当PK(PrimaryKey)匹配时,它进行更新,否则插入。

BulkInsertOrUpdateOrDelete有效地将表行与输入数据同步。

在列表中找不到的Db中的那些将被删除。

BulkRead根据Config中指定的一个或多个“唯一”列进行SELECT和JOIN UpdateByProperties。

在github上的的示例中有更多信息。

性能

以下是性能(对于SQL Server以秒为单位):

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

TestTable有6列(Guid,string,string,int,decimal?,DateTime)。

全部插入,其中2个(字符串,DateTime)已更新。

测试是在以下配置下本地完成的:INTEL Core i5-3570K 3.40GHz,DDRIII 8GB x 2,SSD 840 EVO 128 GB。

对于小型数据集,这会产生开销,因为大多数Bulk op都需要创建Temp表并在完成后将其删除。最好的建议是将Bulk ops用于大于1000的集合。

 

EFCore.BulkExtensions
https://github.com/borisdj/EFCore.BulkExtensions

1条评论

留下评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注