SqlBulkCopy ColumnMapping错误

时间:2014-02-26 11:28:13

标签: c# sql datatable sqlbulkcopy

我的目标是将通用表从一个数据库复制到另一个数据库。我想让它按原样复制数据,如果有新列,可以删除表中的任何内容或添加新列。我唯一想要改变的是添加版本控制的东西,可以在查询的单独部分中完成。

打开数据没问题,但是当我尝试批量复制但是失败时。我已经去了几个帖子,最接近的是这个: 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);
    }
}

3 个答案:

答案 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);

谢谢!!