将 .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 日:初始版本


