如何防止SqlBulkCopy批量复制数据时修改XML列的字符串表示
问题根因说明
SQL Server的XML数据类型本身存储的是解析后的XML信息集(Infoset),不会保留原始字符串的非语义化格式差异,<Item></Item>和<Item/>语义完全等价,写入XML类型列时数据库会自动统一格式,该行为并非SqlBulkCopy主动修改导致。如果要求字符串表示完全一致,无法通过XML类型列实现,必须通过字符串类型存储原始XML内容。
适配方案(无需提前感知XML列,无需修改原有查询SQL)
你可以在adapter.Fill(table)之后,动态识别DataTable中的XML列并转换为字符串类型,完全不依赖前置的SQL生成逻辑,修改后的完整代码如下:
using (SqlDataAdapter adapter = new SqlDataAdapter(source_command)) { using (DataTable table = new DataTable()) { adapter.Fill(table); // 新增逻辑:动态识别并转换XML列为字符串列 List<DataColumn> xmlColumns = new List<DataColumn>(); foreach (DataColumn col in table.Columns) { // DataTable读取SQL Server XML列的默认返回类型为XmlNode if (col.DataType == typeof(System.Xml.XmlNode)) { xmlColumns.Add(col); } } foreach (var xmlCol in xmlColumns) { string tempColName = $"temp_{xmlCol.ColumnName}"; // 新增字符串类型临时列存储原始XML字符串 table.Columns.Add(tempColName, typeof(string)); foreach (DataRow row in table.Rows) { if (row.IsNull(xmlCol)) { row[tempColName] = DBNull.Value; } else { // OuterXml即为源库读取到的原始XML字符串 row[tempColName] = ((System.Xml.XmlNode)row[xmlCol]).OuterXml; } } // 替换原XML列为字符串列 table.Columns.Remove(xmlCol); table.Columns[tempColName].ColumnName = xmlCol.ColumnName; } using (SqlConnection destination = new SqlConnection(destination_connectionstring)) { destination.Open(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destination, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls | SqlBulkCopyOptions.CheckConstraints, null)) { bulkCopy.DestinationTableName = destination_table; bulkCopy.BulkCopyTimeout = 1200; foreach (DataColumn column in table.Columns) { bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(column.ColumnName, column.ColumnName)); } try { bulkCopy.WriteToServer(table); } catch (Exception ex) { Log.Logger.Error(ex.ToString()); throw; } finally { table.Dispose(); } } } } }
注意事项
你需要提前将目标库对应表的XML列调整为nvarchar(max)类型,否则写入XML类型列时仍然会被数据库自动格式化,无法保留原始字符串格式。
内容的提问来源于stack exchange,提问作者Robert Wolf
相关产品推荐
相关产品推荐

