using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Ant.Service.Utility { public enum Gender { Man = 1, Woman } public class User { public Guid Id { get; set; } public string Name { get; set; } public Gender? Gender { get; set; } public int? Age { get; set; } public int? CityId { get; set; } public DateTime? OpTime { get; set; } } public static class SqlConnectionExtension { /// /// 测试代码 /// public static void test() { List usersToInsert = new List(); usersToInsert.Add(new User() { Id = Guid.NewGuid(), Name = "so1", Gender = Gender.Man, Age = 18, CityId = 1, OpTime = DateTime.Now }); usersToInsert.Add(new User() { Id = Guid.NewGuid(), Name = "so2", Gender = Gender.Man, Age = 19, CityId = 2, OpTime = DateTime.Now }); usersToInsert.Add(new User() { Id = Guid.NewGuid(), Name = "so3", Gender = Gender.Man, Age = 20, CityId = 3, OpTime = DateTime.Now }); usersToInsert.Add(new User() { Id = Guid.NewGuid(), Name = "so4", Gender = Gender.Man, Age = 21, CityId = 4, OpTime = DateTime.Now }); using (SqlConnection conn = new SqlConnection("Data Source = .;Initial Catalog = Chloe;Integrated Security = SSPI;")) { conn.BulkCopy(usersToInsert, 20000, "Users"); } } /// /// 使用 SqlBulkCopy 向 destinationTableName 表插入数据 /// /// 必须拥有与目标表所有字段对应属性 /// /// 要插入的数据 /// SqlBulkCopy.BatchSize每次传输的行数 /// 如果为 null,则使用 TModel 名称作为 destinationTableName /// SqlBulkCopy.BulkCopyTimeout /// 要使用的事务 public static void BulkCopy(this SqlConnection conn, List modelList, int batchSize, string destinationTableName = null, int? bulkCopyTimeout = null, SqlTransaction externalTransaction = null) { bool shouldCloseConnection = false; if (string.IsNullOrEmpty(destinationTableName)) destinationTableName = typeof(TModel).Name; DataTable dtToWrite = ToSqlBulkCopyDataTable(modelList, conn, destinationTableName); SqlBulkCopy sbc = null; try { if (externalTransaction != null) sbc = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, externalTransaction); else sbc = new SqlBulkCopy(conn); using (sbc) { sbc.BatchSize = batchSize;//每次传输的行数 sbc.DestinationTableName = destinationTableName; if (bulkCopyTimeout != null) sbc.BulkCopyTimeout = bulkCopyTimeout.Value; if (conn.State != ConnectionState.Open) { shouldCloseConnection = true; conn.Open(); } sbc.WriteToServer(dtToWrite); } } finally { if (shouldCloseConnection && conn.State == ConnectionState.Open) conn.Close(); } } /// /// /// /// /// /// /// /// public static DataTable ToSqlBulkCopyDataTable(List modelList, SqlConnection conn, string tableName) { DataTable dt = new DataTable(); Type modelType = typeof(TModel); List columns = GetTableColumns(conn, tableName); List mappingProps = new List(); var props = modelType.GetProperties(); for (int i = 0; i < columns.Count; i++) { var column = columns[i]; PropertyInfo mappingProp = props.Where(a => a.Name == column.Name).FirstOrDefault(); if (mappingProp == null) throw new Exception(string.Format("model 类型 '{0}'未定义与表 '{1}' 列名为 '{2}' 映射的属性", modelType.FullName, tableName, column.Name)); mappingProps.Add(mappingProp); Type dataType = GetUnderlyingType(mappingProp.PropertyType); if (dataType.IsEnum) dataType = typeof(int); dt.Columns.Add(new DataColumn(column.Name, dataType)); } foreach (var model in modelList) { DataRow dr = dt.NewRow(); for (int i = 0; i < mappingProps.Count; i++) { PropertyInfo prop = mappingProps[i]; object value = prop.GetValue(model); if (GetUnderlyingType(prop.PropertyType).IsEnum) { if (value != null) value = (int)value; } dr[i] = value ?? DBNull.Value; } dt.Rows.Add(dr); } return dt; } /// /// 获取表中所有列 /// /// /// /// static List GetTableColumns(SqlConnection sourceConn, string tableName) { string sql = string.Format("select * from syscolumns inner join sysobjects on syscolumns.id=sysobjects.id where sysobjects.xtype='U' and sysobjects.name='{0}' order by syscolumns.colid asc", tableName); List columns = new List(); using (SqlConnection conn = (SqlConnection)((ICloneable)sourceConn).Clone()) { conn.Open(); SqlCommand command = new SqlCommand(sql, conn); using (var reader = command.ExecuteReader()) { while (reader.Read()) { SysColumn column = new SysColumn(); column.Name = reader["name"].ToString(); column.ColOrder = reader["colorder"].ToInt32(); columns.Add(column); } } conn.Close(); } return columns; } static Type GetUnderlyingType(Type type) { Type unType = Nullable.GetUnderlyingType(type); ; if (unType == null) unType = type; return unType; } class SysColumn { public string Name { get; set; } public int ColOrder { get; set; } } } }