/// <summary> /// 为 MySql.Data 组件提供的用于批量操作的方法。 /// </summary> public sealed class MySqlBatcher : IBatcherProvider
{
/// <summary> /// 获取或设置提供者服务的上下文。 /// </summary> public ServiceContext ServiceContext {
get;
set; }
/// <summary> /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。 /// </summary> /// <param name="dataTable"> 要批量插入的 <see cref="DataTable"/> 。 </param> /// <param name="batchSize"> 每批次写入的数据量。 </param> public void Insert(DataTable dataTable,
int batchSize =
10000)
{
Checker.ArgumentNull(dataTable,
" dataTable ");
if (dataTable.Rows.Count ==
0)
{
return;
}
using (
var connection = ServiceContext.Database.CreateConnection())
{
try {
connection.TryOpen();
using (
var command = ServiceContext.Database.Provider.DbProviderFactory.CreateCommand())
{
if (command ==
null)
{
throw new BatcherException(
new ArgumentException(
" command "));
}
command.Connection = connection;
command.CommandText = GenerateInserSql(ServiceContext.Database, command, dataTable);
if (command.CommandText ==
string.Empty)
{
return;
}
command.ExecuteNonQuery();
}
}
catch (Exception exp)
{
throw new BatcherException(exp);
}
finally {
connection.TryClose();
}
}
}
/// <summary> /// 生成插入数据的sql语句。 /// </summary> /// <param name="database"></param> /// <param name="command"></param> /// <param name="table"></param> /// <returns></returns> private string GenerateInserSql(IDatabase database, DbCommand command, DataTable table)
{
var names =
new StringBuilder();
var values =
new StringBuilder();
var types =
new List<DbType>();
var count = table.Columns.Count;
var syntax = database.Provider.GetService<ISyntaxProvider>();
table.EachColumn(c =>
{
if (names.Length >
0)
{
names.Append(
" , ");
}
names.AppendFormat(
" {0} ", DbUtility.FormatByQuote(syntax, c.ColumnName));
types.Add(c.DataType.GetDbType());
});
var i =
0;
foreach (DataRow row
in table.Rows)
{
if (i >
0)
{
values.Append(
" , ");
}
values.Append(
" ( ");
for (
var j =
0; j < count; j++)
{
if (j >
0)
{
values.Append(
" , ");
}
var isStrType = IsStringType(types[j]);
var parameter = CreateParameter(database.Provider, isStrType, types[j], row[j], syntax.ParameterPrefix, i, j);
if (parameter !=
null)
{
values.Append(parameter.ParameterName);
command.Parameters.Add(parameter);
}
else if (isStrType)
{
values.AppendFormat(
" '{0}' ", row[j]);
}
else {
values.Append(row[j]);
}
}
values.Append(
" ) ");
i++;
}
return string.Format(
" INSERT INTO {0}({1}) VALUES {2} ", DbUtility.FormatByQuote(syntax, table.TableName), names, values);
}
/// <summary> /// 判断是否为字符串类别。 /// </summary> /// <param name="dbType"></param> /// <returns></returns> private bool IsStringType(DbType dbType)
{
return dbType == DbType.AnsiString || dbType == DbType.AnsiStringFixedLength || dbType == DbType.String || dbType == DbType.StringFixedLength;
}
/// <summary> /// 创建参数。 /// </summary> /// <param name="provider"></param> /// <param name="isStrType"></param> /// <param name="dbType"></param> /// <param name="value"></param> /// <param name="parPrefix"></param> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> private DbParameter CreateParameter(IProvider provider,
bool isStrType, DbType dbType,
object value,
char parPrefix,
int row,
int col)
{
// 如果生成全部的参数,则速度会很慢,因此,只有数据类型为字符串(包含'号)和日期型时才添加参数 if ((isStrType && value.ToString().IndexOf(
' \' ') != -
1) || dbType == DbType.DateTime)
{
var name =
string.Format(
" {0}p_{1}_{2} ", parPrefix, row, col);
var parameter = provider.DbProviderFactory.CreateParameter();
parameter.ParameterName = name;
parameter.Direction = ParameterDirection.Input;
parameter.DbType = dbType;
parameter.Value = value;
return parameter;
}
return null;
}
}