2023-07-04 06:15:51
在C#中执行数据库批量更新时,SqlBulkCopy仅支持批量插入,无法直接完成UPDATE操作。以下是几种高效实现批量更新的方法,结合SQL Server特性与C#代码示例:
1. 表值参数(TVP)+ MERGE语句(推荐)原理:通过用户定义表类型(UDT)将数据批量传入存储过程,利用MERGE语句实现“存在则更新,不存在则插入”。步骤:
SQL Server端:
-- 创建表类型CREATE TYPE dbo.UserUpdateType AS TABLE ( Id INT PRIMARY KEY, Name NVARCHAR(50), Email NVARCHAR(100));-- 创建存储过程CREATE PROCEDURE UpdateUsers (@updates dbo.UserUpdateType READONLY)ASMERGE Users AS targetUSING @updates AS sourceON target.Id = source.IdWHEN MATCHED THEN UPDATE SET Name = source.Name, Email = source.Email;C#端:
var table = new DataTable();table.Columns.Add("Id", typeof(int));table.Columns.Add("Name", typeof(string));table.Columns.Add("Email", typeof(string));// 添加数据table.Rows.Add(1, "张三", "zhang@example.com");table.Rows.Add(2, "李四", "li@example.com");using (var conn = new SqlConnection(connectionString)) { conn.Open(); using (var cmd = new SqlCommand("UpdateUsers", conn)) { cmd.CommandType = CommandType.StoredProcedure; var param = cmd.Parameters.AddWithValue("@updates", table); param.SqlDbType = SqlDbType.Structured; param.TypeName = "dbo.UserUpdateType"; cmd.ExecuteNonQuery(); }}优势:单次数据库往返,支持复杂逻辑,适合大数据量。
2. 使用Entity Framework扩展库EF Core原生通过SaveChanges()逐条提交,性能较差。推荐以下扩展库:
适用场景:已使用EF Core的项目,需快速集成批量操作。
3. 拼接SQL批量语句(小批量适用)通过CASE WHEN或参数化查询拼接UPDATE语句,适合几百条数据:
var ids = new[] { 1, 2 };var names = new[] { "张三", "李四" };var emails = new[] { "zhang@ex.com", "li@ex.com" };var sql = @"UPDATE Users SET Name = CASE Id WHEN @id1 THEN @name1 WHEN @id2 THEN @name2 END, Email = CASE Id WHEN @id1 THEN @email1 WHEN @id2 THEN @email2 END WHERE Id IN (@id1, @id2)";using (var conn = new SqlConnection(connectionString)) { conn.Open(); using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue("@id1", ids[0]); cmd.Parameters.AddWithValue("@id2", ids[1]); cmd.Parameters.AddWithValue("@name1", names[0]); cmd.Parameters.AddWithValue("@name2", names[1]); cmd.Parameters.AddWithValue("@email1", emails[0]); cmd.Parameters.AddWithValue("@email2", emails[1]); cmd.ExecuteNonQuery(); }}注意:SQL语句长度受限,大数据量易出错。
4. 临时表 + UPDATE JOIN结合SqlBulkCopy的高速写入与SQL的灵活更新:
// 1. 创建临时表using (var conn = new SqlConnection(connectionString)) { conn.Open(); using (var cmd = new SqlCommand(@" CREATE TABLE #TempUpdates (Id INT, Name NVARCHAR(50), Email NVARCHAR(100))", conn)) { cmd.ExecuteNonQuery(); } // 2. 用SqlBulkCopy写入临时表 var tempTable = new DataTable(); tempTable.Columns.Add("Id", typeof(int)); tempTable.Columns.Add("Name", typeof(string)); tempTable.Columns.Add("Email", typeof(string)); tempTable.Rows.Add(1, "张三", "zhang@ex.com"); tempTable.Rows.Add(2, "李四", "li@ex.com"); using (var bulkCopy = new SqlBulkCopy(conn)) { bulkCopy.DestinationTableName = "#TempUpdates"; bulkCopy.WriteToServer(tempTable); } // 3. 执行UPDATE JOIN using (var cmd = new SqlCommand(@" UPDATE u SET u.Name = t.Name, u.Email = t.Email FROM Users u INNER JOIN #TempUpdates t ON u.Id = t.Id", conn)) { cmd.ExecuteNonQuery(); }}优势:利用SqlBulkCopy快速导入,适合超大数据量。
总结建议