当涉及新老系统迁移的时候,可能同一个模块的数据表结构变化十分大,则需要通过编写一些程序来进行一些转换操作,转换完之后尝尝少则几万条数据,多则几十万条,如果一条一条的插入所消耗的时间成本是十分昂贵的。
那么在C#当中则提供了SqlBulkCopy
类,它存在于System.Data.SqlClient
命名空间下,该类可以进行大批量的数据插入,并且效率十分快。
经过测试,耗时时间如下:
- 十万条数据:2.2051s
- 一万条数据:0.2188s
- 一千条数据:0.0187s
效率十分的高,但是该类仅支持DataTable操作,一般来说Dapper以及EF框架读出来的都是一个IEnumerable,所以我们需要通过反射来构建一个DataTable进行操作。这里我写了一个静态泛型方法,可以直接传入IEnumerbale对象来批量插入数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
static void BulkInsertAll<T>(IEnumerable<T> entities,String connectString)
{
var conn = new SqlConnection(connectString);
conn.Open();
Type t = typeof(T);
var tableAttribute = (TableAttribute)t.GetCustomAttributes(typeof(TableAttribute), false).Single();
var bulkCopy = new SqlBulkCopy(conn) { DestinationTableName = tableAttribute.Name };
var properties = t.GetMembers().Where(p =>
{
var columnAttribute = Attribute.GetCustomAttribute(p, typeof(ColumnAttribute)) as ColumnAttribute;
if (columnAttribute != null) return true;
return false;
}).ToArray();
var table = new DataTable();
foreach (var property in properties)
{
Type propertyType = ((FieldInfo)property).FieldType;
if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
var cols = properties.Select(property =>
{
var field = (FieldInfo)property;
var o = field.GetValue(entity);
if (o == null)
return DBNull.Value;
else
return o;
}).ToArray();
table.Rows.Add(cols);
}
bulkCopy.WriteToServer(table);
conn.Close();
}
}
|