C#中用EF+SqlBulkCopy批量导入SqlServer数据库数据
需求是将Excel中的数据批量导入到SqlServer中。
用EF的Add逐条插入2000条记录需要38s。
其中的操作主要由Excel读到实体类,再由内存写入数据库,耗时很长。
经网上查找,选择SqlBulkCopy类来实现批量导入,修改代码后,再次导入Excel文件数据到SqlServer数据库,耗时不到1s。
首先将实体类转成DataTable
public static DataTable List2DataTable<T>(this List<T> datas) { DataTable dt = new DataTable(); PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { dt.Columns.Add(prop.Name); } foreach (var item in datas) { var values = new object[props.Length]; for (int i = 0; i < props.Length; i++) { values[i] = props[i].GetValue(item, null); } dt.Rows.Add(values); } return dt; }
再将DataTable数据导入到数据库
public void BulkCopy(List<T> entitys) { DataTable dt = ConvertTypeHelper.List2DataTable(entitys); using( SqlBulkCopy bulkCopy=new SqlBulkCopy(Db.Database.Connection.ConnectionString,SqlBulkCopyOptions.UseInternalTransaction)) { bulkCopy.DestinationTableName = typeof(T).Name; bulkCopy.WriteToServer(dt); } }
SqlBulkCopy类创建的时候第一个参数传入连接用的SqlConnection实例或是SqlServer连接字符串,我第二个参数传入的SqlBulkCopyOptions.UseInternalTransaction是将每一批操作在事务中发生,下面是在文档中查到的SqlBulkCopyOptions枚举选项。
我之前传入的是SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.UseInternalTransaction,但是在导入时抛出异常
原因是由于Excel文件中对应的ID字段在数据库中是自增的主键,但这个值在Excel中出现重复,去掉SqlBulkCopyOptions.KeepIdentity,将在插入的时候忽视Excel中该列记录,由系统自动生成。
第三个参数SqlTransaction是传入一个现有的事务,第二个参数提供的可自带事务只能对批量复制导入数据在事务中执行,若需要将其它操作将批量复制导入添加到一个事务里,需要这里传入一个现有事务。
SqlBulkCopyOptions与SqlTransaction只能有一个位置传入事务参数。第二个参数options如果包括UseInternalTransaction,第三个参数又传入了一个现有事务,则会抛出InvalidArgumentException异常。