C# 平时碰见的问题【1】

1. SqlBulkCopy

可以利用这个类实现快速大批量新增数据的效果, 但在使用过程中发现了一个问题: 无法将数据源中的DateTime类型转换成数据库中的int类型

看起来就是数据列不对应导致的, 不过一开始也不确定,后面试验确定 SqlBulkCopy 自建的DataTable数据源writeToServer在未添加列与列的映射(ColumnMappings)时候即使列名一致 也并不是按列名写入数据的,而是按列的索引进行添加的.

故解决方法有二个:

  (1) 在自建的数据源DataTable中补充前面的列 (若列处于需要添加的字段后面 则不用);

  (2) SqlBulkCopy 列映射集合中添加 sqlBulkCopy.ColumnMappings.Add(sourceColumn, destinationColumn);  将每列与目标数据库中的表关联;

代码如下:

         public bool BulkAddData(string recordsString)
{
string[] records = recordsString.Split('$');
bool boolIsSuccess = false;
DataTable dtTemp = new DataTable();
dtTemp.Columns.Add(new DataColumn("ID", typeof(int))); //(1)ID在目标表中是自增列,并且是第一列
dtTemp.Columns.Add(new DataColumn("ScanUserID", typeof(int)));
dtTemp.Columns.Add(new DataColumn("ScanDate", typeof(DateTime)));
dtTemp.Columns.Add(new DataColumn("PO", typeof(string)));
dtTemp.Columns.Add(new DataColumn("SerialNumber", typeof(string)));
dtTemp.Columns.Add(new DataColumn("Container", typeof(string)));
dtTemp.Columns.Add(new DataColumn("ModelName", typeof(string)));
dtTemp.Columns.Add(new DataColumn("ModelID", typeof(int))); foreach (string record in records)
{
DataRow dr = dtTemp.NewRow();
string[] strModel = record.Split(',');
if (strModel.Length == )
{
// ID是自增列,不用赋值
dr["ScanUserID"] = int.Parse(strModel[]);
dr["ScanDate"] = DateTime.Parse(strModel[]);
dr["PO"] = strModel[];
dr["SerialNumber"] = strModel[];
dr["Container"] = strModel[];
dr["ModelName"] = strModel[];
dr["ModelID"] = int.Parse(strModel[]);
}
dtTemp.Rows.Add(dr);
}
string strConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString();
using (SqlConnection conn = new SqlConnection(strConnectionString))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction();
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran);
sqlBulkCopy.DestinationTableName = "T_DeliveryRecord";
sqlBulkCopy.BatchSize = dtTemp.Rows.Count;
//(2) SqlBulkCopy 的表映射默认是按索引来和目标表对应的, 可通过以下方法强制对应
//sqlBulkCopy.ColumnMappings.Add("ScanUserID", "ScanUserID");
//sqlBulkCopy.ColumnMappings.Add("ScanDate", "ScanDate");
//sqlBulkCopy.ColumnMappings.Add("PO", "PO");
//sqlBulkCopy.ColumnMappings.Add("SerialNumber", "SerialNumber");
//sqlBulkCopy.ColumnMappings.Add("Container", "Container");
//sqlBulkCopy.ColumnMappings.Add("ModelName", "ModelName");
//sqlBulkCopy.ColumnMappings.Add("ModelID", "ModelID"); try
{
sqlBulkCopy.WriteToServer(dtTemp);
tran.Commit();
boolIsSuccess = true;
}
catch
{
tran.Rollback();
boolIsSuccess = false;
}
finally
{
sqlBulkCopy.Close();
}
} return boolIsSuccess;
}

ID是我的主键自增的列,位于表的第一位, 所以dtTemp中没有ID列的时候 ScanDate的数据 将插入数据库中的ScanUserID这个int类型的字段中出现上面提到的类型错误; 也就是列的不对应;

所以用方法(1) 解决本问题时, 临时数据表的字段名及顺序需要与目标表一致, 有默认值或者自增的字段不需要赋值; 当然这种情况的列只是作为占位,字段名不用对应也可以:如上面的dtTemp.Columns.Add(new DataColumn("ID", typeof(int))) 改成 dtTemp.Columns.Add(new DataColumn("AA", typeof(int))) 一样也是可以的 );

attention: 注意如果给自增列赋值且SqlBulkCopyOptions.KeepIdentity 将导致目标表该自增列的自增失效;

上一篇:JavaScript确定一个字符串是否包含在另一个字符串中的四种方法


下一篇:access 2007 vba 开发中学到的知识(二)