65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.07/5 (10投票s)

2018 年 1 月 15 日

CPOL

2分钟阅读

viewsIcon

39216

downloadIcon

1300

本文介绍了一种简单而有效的方法,可以将任何 .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();
}

运行测试

先决条件

  1. 在 SQL Server 数据库上执行 *AdapterTests/DbScripts* 文件夹下的 Db 脚本文件。
    • Create_Table_Customer.sql
    • Create_Table_Skus.sql
  2. 修改 app.config 中的连接字符串以指向上述数据库。

测试用例演示了以下场景

应该将列表插入数据库

当 .NET 类型的属性和数据库列名称在名称和定义顺序方面完全匹配时。

应该使用列映射将列表插入数据库

当 .NET 类型的属性名称与数据库列名称不匹配时。

在这种情况下,需要为 SqlBulkCopy 提供一个列映射列表,以帮助它识别哪些属性对应于数据库中的哪些列。

历史

  • 2018 年 1 月 15 日:初始版本
© . All rights reserved.