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; }
}
}
}