【问题标题】:SqlBulkCopy ColumnMapping ErrorSqlBulkCopy 列映射错误
【发布时间】:2014-03-29 04:43:19
【问题描述】:

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

打开数据没问题,但是当我尝试批量复制时却失败了。我浏览了几篇文章,最接近的是这篇文章: 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);
    }
}

【问题讨论】:

    标签: c# sql datatable sqlbulkcopy


    【解决方案1】:

    如果我可以建议另一种方法,我会查看SMO(SQL Server 管理对象)库来执行此类任务。 你可以找到一篇有趣的文章here。 使用 SMO,您可以在 SQL Server 中执行任务,例如批量复制,将表、列和数据库视为对象。

    前段时间,我在自己开发的一个小型开源应用程序中使用了SMO,名为SQLServerDatabaseCopy。 为了将数据从一个表复制到另一个表,我创建了这段代码(完整代码为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】:

      我会为此添加一些验证,以检查您的源表和目标表有哪些共同的列。

      这实质上是查询系统视图(我假设是 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);
              }
          }
      

      由于没有数据类型检查,这仍然可能导致无效转换错误,但应该让您开始使用泛型方法。

      【讨论】:

      • 啊这可行,但它是从目标表中获取名称,而不是从数据表的源表中获取名称。这是我的问题与我在 StackOverflow 中找到的其他问题的不同之处。
      • 我不确定我是否理解问题所在?您可以使用dataTable.Columns获取源表中的列,无论是比较Source与Destination,还是Destination与Source,匹配的列列表仍然相同。
      • 好的,让我澄清一下。我可以得到这些列,得到它们根本不是问题。我的希望是不需要得到它们。我想将 dataTable 原样复制到 SQL 表中。 c#相当于:SELECT * into dbo.test(destination table) FROM dataTable(c# dataTable source table)
      • 你可以使用 SSIS 吗?听起来Transfer SQL Server Objects Task 非常接近您的需要。虽然它不是通用的,但您必须指定您的表。或者你可以使用the underlying DDL 来实现一些东西,但我还没有真正探索过这个选项。
      【解决方案3】:

      你可以添加

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

      谢谢!!

      【讨论】:

        猜你喜欢
        • 2019-02-17
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多