BulkInsert in Entity Framework

news2024/11/8 23:34:33

实体框架中的 BulkInsert 扩展方法

安装 Z.EntityFramework.Extensions:

现在,我将向您展示如何使用 Z.EntityFramework.Extensions 包,以及如何通过 Entity Framework 执行批量插入、更新和删除操作。首先,打开“NuGet 包管理器控制台”窗口并搜索 Z.EntityFramework.Extensions 包。选择“Z.EntityFramework.Extensions”,然后选择“项目”并选择最新版本,最后单击“安装”按钮,如下图所示。

单击“安装”按钮后,将需要一些时间并将 Z.EntityFramework.Extensions DLL 安装到您的项目中。

注意:此 Z.EntityFramework.Extensions 使用高性能批量操作(如 BulkSaveChanges、BulkInsert、BulkUpdate、BulkDelete、BulkMerge 等)扩展了我们的 DbContext 对象。它支持 SQL Server、MySQL、Oracle、PostgreSQL、SQLite 等!

使用实体框架扩展的优点:
  1. 易于使用。
  2. 灵活。
  3. 提高性能。
  4. 提高应用程序响应能力。
  5. 通过减少数据库往返次数来减少数据库负载。
BulkInsert 扩展方法:

Z.EntityFramework.Extensions 提供了两种方法,即 BulkInsert 和 BulkInsertAync,它们允许我们一次性将大量实体插入数据库。使用批量插入扩展方法的语法如下:

context.BulkInsert(listStudents); 
context.BulkInsertAsync(listStudents, cancellationToken);

了解使用实体框架扩展的 BulkInsert 方法的示例

在下面的示例中,我们将使用 BulkInsert 扩展方法将学生列表(即 newStudents)插入数据库。在这里,我们不需要在执行大容量插入操作时调用 SaveChanges 方法。在本例中,使用单次往返,上下文类将执行 INSERT 操作。

using System;
using System.Collections.Generic;
using System.Linq;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("BulkInsert Method Started");
            IList<Student> newStudents = new List<Student>() {
                new Student() { FirstName = "John", LastName = "Taylor", StandardId = 1 },
                new Student() { FirstName = "Sara", LastName = "Taylor", StandardId = 1 },
                new Student() { FirstName = "Pam", LastName= "Taylor", StandardId = 1 },
            };
            using (var context = new EF_Demo_DBEntities())
            {
                context.Database.Log = Console.Write;
                // Easy to use
                context.BulkInsert(newStudents);
            }
            Console.WriteLine("BulkInsert Method Completed");
            GetStudents("Taylor");
            Console.Read();
        }

        public static void GetStudents(string LastName)
        {
            using (var context = new EF_Demo_DBEntities())
            {
                var studentsList = context.Students.Where(std => std.LastName.Equals(LastName, StringComparison.InvariantCultureIgnoreCase));
                foreach (var std in studentsList)
                {
                    Console.WriteLine($"FirstName : {std.FirstName}, LastName : {std.LastName}, StandardId : {std.StandardId}");
                }
            }
        }
    }
}

运行上述代码时,将获得以下输出。请仔细观察 SQL 查询,您将看到它正在使用 SQL Merge 来执行 BULK 操作。由于它减少了与数据库服务器的往返次数,因此大大提高了应用程序性能。

BulkInsert Method Started
Opened connection at 12-12-2022 19:45:45 +05:30
-- Executing Command:

/* SELECT server information */
SELECT  @@VERSION

/* SELECT table information */
SELECT  DestinationTable.Name AS DestinationName ,
        ( SELECT    1
          WHERE     EXISTS ( SELECT 1
                             FROM   sys.triggers AS X
                             WHERE  X.parent_id = A.object_id
                                    AND X.is_disabled = 0
                                    AND OBJECTPROPERTY(X.object_id,
                                                       'ExecIsInsertTrigger') = 1 )
        ) AS HasInsertTrigger ,
        ( SELECT    1
          WHERE     EXISTS ( SELECT 1
                             FROM   sys.triggers AS X
                             WHERE  X.parent_id = A.object_id
                                    AND X.is_disabled = 0
                                    AND OBJECTPROPERTY(X.object_id,
                                                       'ExecIsUpdateTrigger') = 1 )
        ) AS HasUpdateTrigger ,
        ( SELECT    1
          WHERE     EXISTS ( SELECT 1
                             FROM   sys.triggers AS X
                             WHERE  X.parent_id = A.object_id
                                    AND X.is_disabled = 0
                                    AND OBJECTPROPERTY(X.object_id,
                                                       'ExecIsDeleteTrigger') = 1 )
        ) AS HasDeleteTrigger
FROM    (SELECT @Table_0 AS Name) AS DestinationTable
        LEFT JOIN sys.synonyms  AS B ON B.object_id = OBJECT_ID(DestinationTable.Name)
                                                                                AND COALESCE(PARSENAME(base_object_name,4), @@SERVERNAME) = @@SERVERNAME
                                                                                AND COALESCE(PARSENAME(base_object_name,3), DB_NAME(DB_ID())) = DB_NAME(DB_ID())
        INNER JOIN sys.tables   AS A ON A.object_id = OBJECT_ID(DestinationTable.Name)
                                        OR A.object_id = OBJECT_ID(B.base_object_name)
ORDER BY DestinationName

/* SELECT column information */
SELECT  DestinationTable.Name AS DestinationName ,
        C.name AS ColumnName ,
        C.column_id AS ColumnOrder ,
        C.precision AS Precision ,
        C.scale AS Scale ,
        C.max_length AS MaxLength ,
        C.collation_name AS Collation ,
        C.Is_Identity AS IsIdentity ,
        ( CASE WHEN EXISTS ( SELECT 1
                             FROM   sys.index_columns AS X
                             WHERE  X.index_id = B.index_id
                                    AND X.object_id = B.object_id
                                    AND X.column_id = C.column_id ) THEN 1
               ELSE 0
          END ) AS IsPrimaryKey ,
        C.system_type_id AS System_Type_Id ,
        D.Name AS TypeName,
        (CASE WHEN E.base_object_name IS NOT NULL THEN 1 ELSE 0 END) AS IsSynonym,
        D.is_user_defined,
        F.name,
                CASE WHEN C.default_object_id  = 0 THEN 'ZZZ_NO_DEFAULT' ELSE ISNULL(OBJECT_DEFINITION(C.default_object_id), 'ZZZ_ERROR_DEFAULT_ZZZ') END AS DefaultValueSql,
        C.is_nullable
FROM    (SELECT @Table_0 AS Name) AS DestinationTable
        LEFT JOIN sys.synonyms  AS E ON E.object_id = OBJECT_ID(DestinationTable.Name)
                                                                                AND COALESCE(PARSENAME(base_object_name,4), @@SERVERNAME) = @@SERVERNAME
                                                                                AND COALESCE(PARSENAME(base_object_name,3), DB_NAME(DB_ID())) = DB_NAME(DB_ID())
        INNER JOIN sys.tables   AS A ON A.object_id = OBJECT_ID(DestinationTable.Name)
                                        OR A.object_id = OBJECT_ID(E.base_object_name)
        LEFT JOIN sys.indexes   AS B ON B.object_id = A.object_id
                                        AND B.is_primary_key = 1
        INNER JOIN sys.columns  AS C ON C.object_id = A.object_id
        INNER JOIN sys.types    AS D ON D.system_type_id = C.system_type_id
                                     AND D.user_type_id = C.user_type_id
        INNER JOIN sys.schemas AS F ON D.schema_id = F.schema_id
ORDER BY DestinationName ,
        ColumnOrder

-- @Table_0: [dbo].[Student] (Type = String, Size = 15)
-- CommandTimeout:30
-- Executing at 12-12-2022 19:45:45
-- Completed at 12-12-2022 19:45:45
-- Result: SqlDataReader


-- Executing Command:
MERGE INTO [dbo].[Student]  AS DestinationTable
USING
(
SELECT TOP 100 PERCENT * FROM (SELECT @0_0 AS [StudentId], @0_1 AS [FirstName], @0_2 AS [LastName], @0_3 AS [StandardId], @0_4 AS ZZZ_Index
UNION ALL SELECT @1_0 AS [StudentId], @1_1 AS [FirstName], @1_2 AS [LastName], @1_3 AS [StandardId], @1_4 AS ZZZ_Index
UNION ALL SELECT @2_0 AS [StudentId], @2_1 AS [FirstName], @2_2 AS [LastName], @2_3 AS [StandardId], @2_4 AS ZZZ_Index) AS StagingTable ORDER BY ZZZ_Index
) AS StagingTable
ON 1 = 2
WHEN NOT MATCHED THEN
    INSERT ( [FirstName], [LastName], [StandardId] )
    VALUES ( [FirstName], [LastName], [StandardId] )
OUTPUT
    $action,
    StagingTable.ZZZ_Index,
    INSERTED.[StudentId] AS [StudentId_zzzinserted]

;
-- @0_0: 0 (Type = Int32, Size = 4)
-- @0_1: John (Type = AnsiString, Size = 100)
-- @0_2: Taylor (Type = AnsiString, Size = 100)
-- @0_3: 1 (Type = Int32, Size = 4)
-- @0_4: 0 (Type = Int32, Size = 0)
-- @1_0: 0 (Type = Int32, Size = 4)
-- @1_1: Sara (Type = AnsiString, Size = 100)
-- @1_2: Taylor (Type = AnsiString, Size = 100)
-- @1_3: 1 (Type = Int32, Size = 4)
-- @1_4: 1 (Type = Int32, Size = 0)
-- @2_0: 0 (Type = Int32, Size = 4)
-- @2_1: Pam (Type = AnsiString, Size = 100)
-- @2_2: Taylor (Type = AnsiString, Size = 100)
-- @2_3: 1 (Type = Int32, Size = 4)
-- @2_4: 2 (Type = Int32, Size = 0)
-- CommandTimeout:120
-- Executing at 12-12-2022 19:45:45
-- Completed at 12-12-2022 19:45:46
-- Result: 3 rows


Closed connection at 12-12-2022 19:45:46 +05:30
BulkInsert Method Completed
FirstName : John, LastName : Taylor, StandardId : 1
FirstName : Sara, LastName : Taylor, StandardId : 1
FirstName : Pam, LastName : Taylor, StandardId : 1

Entity Framework 中 SaveChanges 和 BulkInsert 的性能比较:

让我们通过一个示例来查看 Entity Framework SaveChanges 方法和 BulkInsert 扩展方法之间的性能基准。众所周知,Entity Framework SaveChanges 方法将为每个实体生成并执行单独的 SQL 查询,即多个数据库行程,而 BulkInsert 扩展方法使用单个数据库行程执行相同的任务。

我们将使用两种方法(即 AddRange 方法和 BulkInsert 扩展方法)批量插入 1000 名学生,并将测量两种方法完成任务所需的时间。为了更好地理解,请看以下示例。在下面的示例中,不要考虑使用FirstTimeExecution方法进行性能测试,因为我们知道,当我们第一次执行某些操作时,将花费更多时间。

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace DBFirstApproach
{
    class Program
    {
        static void Main(string[] args)
        {
            //Don't consider below for performance Testing
            //This warmup
            FirstTimeExecution();

            // Generate 1000 Students
            List<Student> studentList = GenerateStudents(1000);
            Stopwatch SaveChangesStopwatch = new Stopwatch();
            Stopwatch BulkInsertStopwatch = new Stopwatch();

            using (EF_Demo_DBEntities context1 = new EF_Demo_DBEntities())
            {
                // Add the Student Collection using the AddRange Method
                context1.Students.AddRange(studentList);
                SaveChangesStopwatch.Start();
                context1.SaveChanges();
                SaveChangesStopwatch.Stop();
                Console.WriteLine($"SaveChanges, Entities : {studentList.Count}, Time Taken : {SaveChangesStopwatch.ElapsedMilliseconds} MS");
            }

            using (EF_Demo_DBEntities context2 = new EF_Demo_DBEntities())
            {
                // BulkInsert
                BulkInsertStopwatch.Start();
                context2.BulkInsert(studentList, options => options.AutoMapOutputDirection = false); // performance can be improved with options
                BulkInsertStopwatch.Stop();
                Console.WriteLine($"BulkInsert, Entities : {studentList.Count}, Time Taken : {BulkInsertStopwatch.ElapsedMilliseconds} MS");
            }

            Console.Read();
        }

        public static void FirstTimeExecution()
        {
            List<Student> stduentsList = GenerateStudents(20);

            // SaveChanges
            using (var context = new EF_Demo_DBEntities())
            {
                context.Students.AddRange(stduentsList);
                //Call the SaveChanges Method to INSERT the data into the database
                context.SaveChanges();
                // Delete the Newly Inserted Data
                context.BulkDelete(stduentsList);
            }

            // BulkInsert
            using (var context = new EF_Demo_DBEntities())
            {
                context.BulkInsert(stduentsList, options => options.AutoMapOutputDirection = false);
                // Delete the Newly Inserted Data
                context.BulkDelete(stduentsList);
            }
        }

        public static List<Student> GenerateStudents(int count)
        {
            var listOfStudents = new List<Student>();

            for (int i = 0; i < count; i++)
            {
                listOfStudents.Add(new Student() { FirstName = "FirstName_" + i, LastName = "LastName_" + i, StandardId = 1 });
            }

            return listOfStudents;
        }
    }
}

现在,运行上面的代码,你将获得以下输出。如您所见,SaveChanges 方法将 1000 个实体插入数据库需要 490 毫秒,而 BulkInsert Extension 方法只需 20 毫秒即可将相同的 1000 个实体插入数据库。因此,可以想象,当考虑性能时,实体框架 AddRange 方法有多危险。

注意: 需要考虑许多影响基准时间的因素,例如索引、列类型、延迟、限制等。

为什么 BulkInsert 扩展方法比 SaveChanges 更快?

插入 1000 个实体进行初始加载或文件导入是典型的方案。由于需要往返的数据库数量,SaveChanges 方法使处理这种情况变得非常缓慢/不可能。SaveChanges 对要插入的每个实体执行一次数据库往返。因此,如果需要插入 10,000 个实体,将执行 10,000 次数据库往返,这会使其变慢。

对应项中的 BulkInsert 需要尽可能少的数据库往返次数。例如,在 SQL Server 的后台,执行 SqlBulkCopy 以插入 10,000 个实体,这是最快的可用方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1164500.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux驱动 编译乱序和执行乱序

编译乱序 现代的高性能编译器在目标码优化上都具备对指令进行乱序优化的能力。编译器可以对访存的指令进行乱序&#xff0c;减少逻辑上不必要的访存&#xff0c;以及尽量提高Cache命中率和CPU的Load/Store单元的工作效率。 因此在打开编译器优化以后&#xff0c;看到生成的汇编…

JAVA亡了?那么多岗位去哪了?

1.java现在有多卷&#xff1f; 虽然近年来出现了许多其他编程语言和技术。但JAVA依旧是热度最高的。它仍然被广泛用于大型企业应用、后端开发、Android应用开发以及嵌入式系统等领域。此外&#xff0c;Java在大数据、云计算和物联网等新兴领域也有着重要的地位。 因此&#x…

MySQL数据库入门到大牛_01_内容简介

在企业中高级程序员以上级别常常要求是精通MySQL。任何一项技术一旦深入&#xff0c;体系都是繁杂的&#xff0c;想要真正掌握&#xff0c;需要掌握底层的逻辑&#xff0c;梳理清知识脉络&#xff0c;能够以架构师的思路学习MySQL&#xff0c;才能以不变应万变。此篇开始介绍My…

Linux-固定usb转网口名称

参考链接 https://www.cnblogs.com/WCH-SoftGroup/p/16516383.htmludev简介 udev 是一个用户空间系统&#xff0c;它使操作系统管理员能够为事件注册用户空间处理程序。 udev 守护程序接收的事件主要由 &#xff08;Linux&#xff09; 内核生成&#xff0c;以响应与外围设备相…

便携式燃料容器上亚马逊加拿大站合规标准是什么?如何办理?

便携式燃料容器 便携式燃料容器是预填充或设计用于容纳易燃液体燃料的一次性或可重复使用的容器。该政策还涵盖用于便携式燃料容器的随附组件&#xff0c;包括用于储存或分配易燃液体燃料的密封罩。 便携式燃料容器亚马逊政策 根据亚马逊政策的要求&#xff0c;所有便携式燃料…

香港「加密货币新政」一周年回顾:怀疑、亢奋和审慎乐观的发展历程

香港作为国际金融中心&#xff0c;一直以来都在追求创新和发展新兴市场。然而&#xff0c;在虚拟资产领域&#xff0c;香港经历了一段怀疑、亢奋和审慎乐观的过程。如今&#xff0c;回顾香港虚拟资产宣言一周年&#xff0c;可以看到这个领域正逐步稳定发展&#xff0c;并得到了…

使用C++的QT框架实现贪吃蛇

最近刷抖音经常看到别人使用类似chatGPT的al工具实现这个贪吃蛇游戏&#xff0c;正好我之前也写过&#xff0c;那么今天看看怎么去实现这个简单的游戏 我这边使用的是C的QT框架&#xff0c;当然用哪些框架都可以&#xff0c;主要是逻辑思路 1.生成画布&#xff0c;开始是一些…

MySQL(6):多表查询

多表查询&#xff0c;也称为关联查询&#xff0c;指两个或更多个表一起完成查询操作。 前提条件&#xff1a; 这些一起查询的表之间是有关系的&#xff08;一对一、一对多&#xff09;&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键&#xff0c;…

医院小程序解决方案:让医疗服务触手可及

随着移动互联网的发展&#xff0c;小程序已经成为各行各业进行营销和提供服务的重要工具。医疗陪诊行业也不例外。本教程将带领大家了解如何快速掌握医疗陪诊小程序的搭建技巧&#xff0c;帮助大家轻松搭建自己的医疗陪诊小程序。 步骤一&#xff1a;登录乔拓云平台进入商城后台…

分类预测 | Matlab实现SMA-KELM黏菌优化算法优化核极限学习机分类预测

分类预测 | Matlab实现SMA-KELM黏菌优化算法优化核极限学习机分类预测 目录 分类预测 | Matlab实现SMA-KELM黏菌优化算法优化核极限学习机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SMA-KELM黏菌优化算法优化核极限学习机分类预测(完整源码和数…

进程空间管理:用户态和内核态

用户态虚拟空间里面有几类数据&#xff0c;例如代码、全局变量、堆、栈、内存映射区等。在 struct mm_struct 里面&#xff0c;有下面这些变量定义了这些区域的统计信息和位置。 unsigned long mmap_base; /* base of mmap area */ unsigned long total_vm; /* Total page…

sql根据同一字段不同值时间升序将序

SELECT ID,T_STATUS,T_TIME FROMs order by CASE WHEN T_STATUS 0 THEN 100 ELSE 1000 END,case when T_STATUS 0 then T_TIME end ,case when T_STATUS ! 0 then T_TIME end desc;

Java规则引擎2.1.8版本新增功能说明

规则引擎更新功能 新增: 1.决策结束节点新增结果导出excel功能&#xff1b; 在决策流程的结束节点&#xff0c;可以将决策结果导出为Excel文件。这个功能为用户提供了更多的灵活性和便利性&#xff0c;使他们能够轻松地将决策结果数据进行进一步的分析和处理。 2.新增公有变…

【教3妹学编程-算法题】2913. 子数组不同元素数目的平方和 I

-----------------第二天------------------------ 面试官 : 好的&#xff0c; 我们再来做个算法题吧。平时工作中会尝试用算法吗&#xff0c; 用到了什么数据结构&#xff1f; 3妹 : 有用到&#xff0c; 用到了 bla bla… 面试官 : 好的&#xff0c; 题目是这样的&#xff1…

kali搭建Cobalt strike挂马

APT攻击是高级可持续化攻击&#xff0c;一般是团队分工合作 Cobalt strike红队用的渗透工具。多协议&#xff0c;端口&#xff0c;插件 服务端运行 cobaltstrike4提示java异常&#xff0c;改用cobaltstrike 3.14版本 服务端搭建&#xff1a;./teamserver 服务器IP地址 密码 …

2G-GCN:Multi-person HOI Recognition in Videos

Geometric Features Informed Multi-person Human-object Interaction Recognition in Videos解读 摘要简介 2. Related Work2.1 图像中的HOI检测2.2 视频中的HOI识别2.3 HOI识别数据集2.4 几何特征为HOI分析提供信息 3. 多人HOI数据集(MPHOI-72)4. Two-level Geometric Featur…

MySQL -- 复合查询及内外连接

MySQL – 复合查询及内外连接 文章目录 MySQL -- 复合查询及内外连接一、基本查询回顾1.单表查询 二、多表查询1.表的组合2.案例 三、自连接1.案例四、子查询1.单行子查询2.多行子查询3.多列子查询4.在from子句中使用子查询5.合并查询 五、内连接六、外连接1.左外连接2.右外连接…

C语言程序设计(第五版)谭浩强 第三章课后题答案

第三章 1、假如我国国民生产总值的年增长率为7%&#xff0c; 计算10年后我国国民生产总值与现在相比增长多少百分比。计算公式为 ,其中r为年增长率&#xff0c;n为年数&#xff0c;p为与现在相比的倍数。 #include<stdio.h> #include<math.h>int main(){float r,…

基于QT的简易计算器(一)

目录 0 简介1.设计原理1.1界面设计1.1.1界面基本布局1.1.2 界面调整和美化1.1.2 控件重命名 1.2 连接信号和槽1.3 软件逻辑1.3.1四则运算1.3.2 连续运算&#xff08;不完全&#xff09;的原理1.3.3 清屏1.3.4 退格1.3.5 等于1.3.6 小数点 2.总结与拓展 0 简介 最近在学QT&…

数字化浪潮下,AI数字人融入多元化应用场景

随着AI数字人技术的发展&#xff0c;各个行业都在不断挖掘数字人更多的潜力&#xff0c;VR全景中的AI数字人功能逐渐成为了一种新颖的用户交互方式。AI数字人将企业的文化、品牌价值、商业服务等充分结合为一体&#xff0c;为企业提供了全新的机会&#xff0c;从客户互动到营销…