C# 平时碰见的问题【1】
1. SqlBulkCopy
可以利用这个类实现快速大批量新增数据的效果, 但在使用过程中发现了一个问题: 无法将数据源中的DateTime类型转换成数据库中的int类型
看起来就是数据列不对应导致的, 不过一开始也不确定,后面试验确定 SqlBulkCopy 自建的DataTable数据源writeToServer在未添加列与列的映射(ColumnMappings)时候即使列名一致 也并不是按列名写入数据的,而是按列的索引进行添加的.
故解决方法有二个:
(1) 在自建的数据源DataTable中补充前面的列 (若列处于需要添加的字段后面 则不用);
(2) SqlBulkCopy 列映射集合中添加 sqlBulkCopy.ColumnMappings.Add(sourceColumn, destinationColumn); 将每列与目标数据库中的表关联;
代码如下:
1 public bool BulkAddData(string recordsString) 2 { 3 string[] records = recordsString.Split('$'); 4 bool boolIsSuccess = false; 5 DataTable dtTemp = new DataTable(); 6 dtTemp.Columns.Add(new DataColumn("ID", typeof(int))); //(1)ID在目标表中是自增列,并且是第一列 7 dtTemp.Columns.Add(new DataColumn("ScanUserID", typeof(int))); 8 dtTemp.Columns.Add(new DataColumn("ScanDate", typeof(DateTime))); 9 dtTemp.Columns.Add(new DataColumn("PO", typeof(string))); 10 dtTemp.Columns.Add(new DataColumn("SerialNumber", typeof(string))); 11 dtTemp.Columns.Add(new DataColumn("Container", typeof(string))); 12 dtTemp.Columns.Add(new DataColumn("ModelName", typeof(string))); 13 dtTemp.Columns.Add(new DataColumn("ModelID", typeof(int))); 14 15 foreach (string record in records) 16 { 17 DataRow dr = dtTemp.NewRow(); 18 string[] strModel = record.Split(','); 19 if (strModel.Length == 7) 20 { 21 // ID是自增列,不用赋值 22 dr["ScanUserID"] = int.Parse(strModel[0]); 23 dr["ScanDate"] = DateTime.Parse(strModel[1]); 24 dr["PO"] = strModel[2]; 25 dr["SerialNumber"] = strModel[3]; 26 dr["Container"] = strModel[4]; 27 dr["ModelName"] = strModel[5]; 28 dr["ModelID"] = int.Parse(strModel[6]); 29 } 30 dtTemp.Rows.Add(dr); 31 } 32 string strConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString(); 33 using (SqlConnection conn = new SqlConnection(strConnectionString)) 34 { 35 conn.Open(); 36 SqlTransaction tran = conn.BeginTransaction(); 37 SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran); 38 sqlBulkCopy.DestinationTableName = "T_DeliveryRecord"; 39 sqlBulkCopy.BatchSize = dtTemp.Rows.Count; 40 //(2) SqlBulkCopy 的表映射默认是按索引来和目标表对应的, 可通过以下方法强制对应 41 //sqlBulkCopy.ColumnMappings.Add("ScanUserID", "ScanUserID"); 42 //sqlBulkCopy.ColumnMappings.Add("ScanDate", "ScanDate"); 43 //sqlBulkCopy.ColumnMappings.Add("PO", "PO"); 44 //sqlBulkCopy.ColumnMappings.Add("SerialNumber", "SerialNumber"); 45 //sqlBulkCopy.ColumnMappings.Add("Container", "Container"); 46 //sqlBulkCopy.ColumnMappings.Add("ModelName", "ModelName"); 47 //sqlBulkCopy.ColumnMappings.Add("ModelID", "ModelID"); 48 49 try 50 { 51 sqlBulkCopy.WriteToServer(dtTemp); 52 tran.Commit(); 53 boolIsSuccess = true; 54 } 55 catch 56 { 57 tran.Rollback(); 58 boolIsSuccess = false; 59 } 60 finally 61 { 62 sqlBulkCopy.Close(); 63 } 64 } 65 66 return boolIsSuccess; 67 }
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 将导致目标表该自增列的自增失效;
本文来自博客园,作者:mushishi,转载请注明原文链接:https://www.cnblogs.com/mushishi/p/3592558.html