1.概述
1.1 背景
使用EF框架对大量数据进行的插入或修改时,性能不高。而EF扩展库的批量修改每次只能修改特定的字段且约束字段也是特定的,当修改的数据是随机时,EF扩展库的批量修改满足我的需求。
1.2 目标
插入大量数据时,为提高性能,使用SqlBulkCopy临时表批量插入。修改大量数据是,先把修改的数据放到内存中,进行修改。然后删除数据库的数据,再用临时表一次插入。
2.解决方案
结合EF框架,使用SqlBulkCopy方法批量插入。
/// <summary>
/// 批量插入
/// </summary>
/// <typeparam name="T">泛型集合的类型</typeparam>
/// <param name=" dbContext ">连接对象</param>
/// <param name="tableName">将泛型集合插入到本地数据库表的表名</param>
/// <param name="list">要插入大泛型集合</param>
public static bool BulkInsert<T>(DbContext dbContext , string tableName, IList<T> list)
{
try
{
if (list == null || list.Count == 0) return true;
if (dbContext.Database.Connection.State != ConnectionState.Open)
{
dbContext.Database.Connection.Open(); //打开Connection连接
}
using (var bulkCopy = new SqlBulkCopy(dbContext.Database.Connection.ConnectionString))
{
bulkCopy.BatchSize = list.Count;
bulkCopy.DestinationTableName = tableName;
var table = new DataTable();
var props = TypeDescriptor.GetProperties(typeof(T))
.Cast<PropertyDescriptor>()
.Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System"))
.ToArray();
foreach (var propertyInfo in props)
{
bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
}
var values = new object[props.Length];
foreach (var item in list)
{
for (var i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
bulkCopy.WriteToServer(table);
if (dbContext.Database.Connection.State != ConnectionState.Closed)
{
dbContext.Database.Connection.Close(); //关闭Connection连接
}
return true;
}
}
catch (Exception ex)
{
if (dbContext.Database.Connection.State != ConnectionState.Closed)
{
dbContext.Database.Connection.Close(); //关闭Connection连接
}
return false;
}
}
调用方法如下:
List<Students> lstStu = new List< Students>();
// lstStu.Add(stu);
if (!DbHelper.BulkInsert< Students>( dbContext, "Students", lstTestStu))
{
return false;
}
3. 解决方案分析
以上方案解决了批量插入的需求。但是要批量修改数据,需要先删除数据库数据,然后再批量插入。这个过程需要使用到事务来保证数据的一致性。这里我使用的是TransactionScope事务。有关TransactionScope使用说明可看“TransactionScope简介”。