惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
博客园 - Franky
The GitHub Blog
The GitHub Blog
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
小众软件
小众软件
罗磊的独立博客
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
C
Check Point Blog
WordPress大学
WordPress大学
博客园 - 【当耐特】
博客园 - 司徒正美
D
Docker

博客园 - 燕闪硕

Python 开发 Windows 客户端:Web 技术做界面的 5 款核心工具 Python描述器(Descriptor)深度解析:OOP底层核心机制实操指南 使用pyenv-win管理多版本Python Python字符串编码及正则表达式使用 利用canvas在手机页面实现景区导航的一点思路 重装系统后遇到Git Authentication failed 错误 [转帖]如何准确高效的获取数据库新插入数据的主键id [转帖]SQL中partition关键字的使用 利用分布类防止EF更新模型丢失验证信息 列表样式切换 CSS3 简易照片墙 HTML5表单增强 HTML5 元素拖放 HTML 5 全局属性 微软build 2015 写个程序登陆58同城 工厂方法 简单工厂 System.Data.SQLite兼容32位和64位问题
EF Core 批量操作实战:3 种方案对比与性能测试
燕闪硕 · 2026-02-01 · via 博客园 - 燕闪硕

本文将对比 3 种 EF Core 批量操作方案:

  1. 第三方库(EFCore.BulkExtensions):简单高效,开箱即用;
  2. 原生 SQL+Dapper:灵活可控,适合复杂批量逻辑;
  3. EF Core 原生事务 + AddRange:无依赖,适合小数据量场景;

并通过真实性能测试,告诉你不同数据量下该选哪种方案。

一、环境准备

1. 基础配置

  • .NET 版本:.NET 10
  • EF Core 
  • 虚拟机+数据库:SQL Server 2019
// 实体模型
public class User
{
    /// <summary>
    /// 主键
    /// </summary>
    public int Id { get; set; }
    
    /// <summary>
    /// 用户名
    /// </summary>
    public string UserName { get; set; } = string.Empty;
    
    /// <summary>
    /// 创建时间
    /// </summary>
    public DateTime CreateTime { get; set; } = DateTime.Now;
}

2. 测试数据生成工具

封装一个生成测试数据的方法,方便后续批量测试:

        public static List<User> GenerateTestUsers(int count)
        {
            var users = new List<User>();
            for (int i = 0; i < count; i++)
            {
                users.Add(new User
                {
                    UserName = $"TestUser_{Guid.NewGuid():N}",
                    CreateTime = DateTime.Now
                });
            }
            return users;
        }

二、三种批量操作方案实现

方案 1:EFCore.BulkExtensions(推荐,高效简洁)

这是 EF Core 生态中最成熟的批量操作库,支持批量新增、更新、删除、合并,底层用 Bulk Insert/Update 实现,性能接近原生 SQL。

        /// <summary>
        /// 方案1:EFCore.BulkExtensions批量操作
        /// </summary>
        /// <param name="users">待插入数据</param>
        public static async Task BulkInsertWithExtension(List<User> users)
        {
            using var dbContext = new AppDbContext();
            // 记录开始时间
            var stopwatch = Stopwatch.StartNew();
            // 批量插入核心代码
            await dbContext.BulkInsertAsync(users);
            stopwatch.Stop();
            Console.WriteLine($"EFCore.BulkExtensions插入{users.Count}条数据耗时:{stopwatch.ElapsedMilliseconds}ms");
        }

TestSQL1

方案 2:原生 SQL+Dapper(灵活,适合复杂场景)

Dapper 是轻量 ORM,执行原生 SQL 的性能几乎和ADO.NET持平,适合需要自定义批量 SQL 的场景(比如批量更新带复杂条件)。

        /// <summary>
        /// 方案2:原生SQL+Dapper批量插入
        /// </summary>
        /// <param name="users">待插入数据</param>
        public static async Task BulkInsertWithDapper(List<User> users)
        {
            using var connection = new SqlConnection(Common.ConnectionString);
            await connection.OpenAsync();
            var stopwatch = Stopwatch.StartNew();

            // 批量插入SQL(表值参数方式,避免SQL注入)
            var sql = @"INSERT INTO Users (UserName, CreateTime)
                        SELECT UserName, CreateTime FROM @Users;";

            // 构造表值参数
            var dataTable = new DataTable();
            dataTable.Columns.Add("UserName", typeof(string));
            dataTable.Columns.Add("CreateTime", typeof(DateTime));

            foreach (var user in users)
            {
                dataTable.Rows.Add(user.UserName, user.CreateTime);
            }

            await connection.ExecuteAsync(sql, new { Users = dataTable.AsTableValuedParameter("dbo.UserTableType") });

            stopwatch.Stop();
            Console.WriteLine($"Dapper+原生SQL插入{users.Count}条数据耗时:{stopwatch.ElapsedMilliseconds}ms");
        }

注意:需要先在 SQL Server 中创建表值类型UserTableType

CREATE TYPE UserTableType AS TABLE (
    UserName NVARCHAR(50),
    CreateTime DATETIME
);

TestSQL2

方案 3:EF Core 原生事务 + AddRange(无依赖,小数据量)

这是 EF Core 原生支持的方案,无需安装任何第三方库,但本质还是逐条生成 SQL(只是通过事务减少提交次数),适合小数据量场景。

        public static async Task BulkInsertWithEFNative(List<User> users)
        {
            using var dbContext = new AppDbContext();
            // 开启事务
            using var transaction = await dbContext.Database.BeginTransactionAsync();
            var stopwatch = Stopwatch.StartNew();
            // 批量添加到上下文
            dbContext.Users.AddRange(users);
            // 一次性提交
            await dbContext.SaveChangesAsync();
            // 提交事务
            await transaction.CommitAsync();
            stopwatch.Stop();
            if (users != null && users.Count >= 100)
                Console.WriteLine($"EF Core原生AddRange插入{users.Count}条数据耗时:{stopwatch.ElapsedMilliseconds}ms");
        }

TestSQL3

  1. 优先选 EFCore.BulkExtensions:90% 的批量场景都适用,代码简洁、性能接近原生 SQL;
  2. 选 Dapper + 原生 SQL:需要自定义复杂批量逻辑(比如批量更新带多条件)、或对第三方库有顾虑;
    当数据表有变动时,修改困难。
  3. 选 EF Core 原生 AddRange:数据量 < 1000、且不想引入任何第三方依赖。