将 .NET 列表批量插入数据库






3.07/5 (10投票s)
本文介绍了一种简单而有效的方法,可以将任何 .NET 列表批量插入数据库。
引言
SqlBulkCopy
类提供了一种将数据导入到 SQL Server 数据库的有效方法。即便如此,它开箱即用,仅支持从以下类型之一导入数据
DataTable
DataRow[]
IDataReader
在本文中,我们将研究一种简单而有效的机制,用于从任何 IList<T>
类型批量插入数据。
背景
有时我们可能需要将 .NET 对象中可用的信息批量上传到数据库。SqlBulkCopy
类允许您有效地将 SQL Server 表与来自另一个源的数据进行批量加载。但是,要利用这一点,我们需要在每个需要批量持久化的类型上实现 IDataReader
,或者将数据重建为 DataTable
(DataRow[]
)。
创建对象数据的 DataTable
版本可能不太理想,尤其是在数据量很大时。
另一方面,在类型上实现 IDataReader
需要定义令人望而生畏的 33 个方法
GetName(int i):string
GetDataTypeName(int i):string
GetFieldType(int i):Type
GetValues(object[] values):int
GetBoolean(int i):bool
GetByte(int i):byte
GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length):long
GetChar(int i):char
GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length):long
GetGuid(int i):Guid
GetInt16(int i):short
GetInt32(int i):int
GetInt64(int i):long
GetFloat(int i):float
GetDouble(int i):double
GetString(int i):string
GetDecimal(int i):decimal
GetDateTime(int i):DateTime
GetData(int i):IDataReader
IsDBNull(int i):bool
this[int i]:object
this[string name]:object
Close():void
GetSchemaTable():DataTable
幸运的是,对于批量复制,只需要定义以下少量方法
Dispose():void
GetValue(int i):object
IsDBNull
GetOrdinal(string name):int
FieldCount:int
Read():bool
Depth:int
IsClosed:bool
RecordsAffected:int
此处介绍的 DataReaderAdapter
类省去了实现这组简化方法的麻烦,只要数据以 IList<T>
的形式呈现即可。 DataReaderAdapter
包装了列表,并将自身公开为 IDataReader
,可直接由 SqlBulkCopy
的 'WriteToServer
' 方法使用。
Using the Code
使用 DataReaderAdapter
非常简单
- 使用需要持久化的类型的
IList
实例化DataReaderAdapter
。 - 将
DataReaderAdapter
传递给SqlBulkCopy.WriteToServer()
方法。
//Generate a list of 10,000 Customer records
var customers = _fixture.CreateMany<Customer>(10000).ToList();
var customerDr = new DataReaderAdapter<Customer>(customers);
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
var bulkCopy = new SqlBulkCopy(connection)
{
DestinationTableName = "[dbo].[Customer]",
BatchSize = 1000
};
bulkCopy.WriteToServer(customerDr);
bulkCopy.Close();
}
运行测试
先决条件
- 在 SQL Server 数据库上执行 *AdapterTests/DbScripts* 文件夹下的 Db 脚本文件。
- Create_Table_Customer.sql
- Create_Table_Skus.sql
- 修改 app.config 中的连接字符串以指向上述数据库。
测试用例演示了以下场景
应该将列表插入数据库
当 .NET 类型的属性和数据库列名称在名称和定义顺序方面完全匹配时。
应该使用列映射将列表插入数据库
当 .NET 类型的属性名称与数据库列名称不匹配时。
在这种情况下,需要为 SqlBulkCopy
提供一个列映射列表,以帮助它识别哪些属性对应于数据库中的哪些列。
历史
- 2018 年 1 月 15 日:初始版本