我的目标是将通用表从一个数据库复制到另一个数据库。我想让它按原样复制数据,如果有新列,可以删除表中的任何内容或添加新列。我唯一想要改变的是添加版本控制的东西,可以在查询的单独部分中完成。
打开数据没问题,但是当我尝试批量复制但是失败时。我已经去了几个帖子,最接近的是这个: SqlBulkCopy Insert with Identity Column
我从代码中删除了SqlBulkCopyOptions.KeepIdentity,但它仍然在抛出
"给定的ColumnMapping与源或目标中的任何列都不匹配"错误
我尝试过使用SqlBulkCopyOptions但到目前为止没有运气。
想法?
public void BatchBulkCopy(string connectionString, DataTable dataTable, string DestinationTbl, int batchSize)
{
// Get the DataTable
DataTable dtInsertRows = dataTable;
using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString))
{
sbc.DestinationTableName = DestinationTbl;
// Number of records to be processed in one go
sbc.BatchSize = batchSize;
// Finally write to server
sbc.WriteToServer(dtInsertRows);
}
}
答案 0 :(得分:3)
我会为此添加一些验证,以检查源表和目标表的共同列。
这本质上是查询系统视图(我已经假定SQL Server,但这很容易适用于其他DBMS),获取目标表中的列名(不包括标识列),迭代这些视图以及是否匹配在源表中添加列映射。
public void BatchBulkCopy(string connectionString, DataTable dataTable, string DestinationTbl, int batchSize)
{
using (SqlBulkCopy sbc = new SqlBulkCopy(connectionString))
{
sbc.DestinationTableName = DestinationTbl;
string sql = "SELECT name FROM sys.columns WHERE is_identity = 0 AND object_id = OBJECT_ID(@table)";
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("@table", DestinationTbl);
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var column = reader.GetString(0);
if (dataTable.Columns.Contains(column))
{
sbc.ColumnMappings.Add(column, column);
}
}
}
}
// Number of records to be processed in one go
sbc.BatchSize = batchSize;
// Finally write to server
sbc.WriteToServer(dataTable);
}
}
由于没有数据类型检查,这仍然可能会导致无效的强制转换错误,但是应该让您开始使用泛型方法。
答案 1 :(得分:3)
如果我可以提出另一种方法,我会查看SMO(SQL Server管理对象)库来执行此类任务。 你可以找到一篇有趣的文章here。 使用SMO,您可以在SQL Server中执行任务,例如批量复制,将表,列和数据库视为对象。
前段时间,我在我开发的一个名为SQLServerDatabaseCopy的小型开源应用程序中使用了SMO。 要将数据从表复制到表,我创建了此代码(完整代码为here):
foreach (Table table in Tables)
{
string columnsTable = GetListOfColumnsOfTable(table);
string bulkCopyStatement = "SELECT {3} FROM [{0}].[{1}].[{2}]";
bulkCopyStatement = String.Format(bulkCopyStatement, SourceDatabase.Name, table.Schema, table.Name, columnsTable);
using (SqlCommand selectCommand = new SqlCommand(bulkCopyStatement, connection))
{
LogFileManager.WriteToLogFile(bulkCopyStatement);
SqlDataReader dataReader = selectCommand.ExecuteReader();
using (SqlConnection destinationDatabaseConnection = new SqlConnection(destDatabaseConnString))
{
if (destinationDatabaseConnection.State == System.Data.ConnectionState.Closed)
{
destinationDatabaseConnection.Open();
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationDatabaseConnection))
{
bulkCopy.DestinationTableName = String.Format("[{0}].[{1}]", table.Schema, table.Name);
foreach (Column column in table.Columns)
{
//it's not needed to perfom a mapping for computed columns!
if (!column.Computed)
{
bulkCopy.ColumnMappings.Add(column.Name, column.Name);
}
}
try
{
bulkCopy.WriteToServer(dataReader);
LogFileManager.WriteToLogFile(String.Format("Bulk copy successful for table [{0}].[{1}]", table.Schema, table.Name));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
finally
{
//closing reader
dataReader.Close();
}
}
}
}
}
如您所见,您必须为每列添加ColumnMappings
到BulkCopy对象,因为您必须定义源表的哪一列必须映射到目标表的列。这就是您的错误原因:The given ColumnMapping does not match up with any column in the source or destination
。
答案 2 :(得分:0)
您可以添加
sbc.ColumnMappings.Add(0, 0);
sbc.ColumnMappings.Add(1, 1);
sbc.ColumnMappings.Add(2, 2);
sbc.ColumnMappings.Add(3, 3);
sbc.ColumnMappings.Add(4, 4);
执行前
sbc.WriteToServer(dataTable);
谢谢!!