在SqlBulkCopy中跳过一些列

时间:2010-09-24 07:13:00

标签: c# sql-server sql-server-2008 sqlbulkcopy columnmappings

我正在使用SqlBulkCopy针对两个具有不同列集的SQL Server 2008(将一些数据从prod服务器移动到dev)。所以想要跳过一些尚未存在/尚未删除的列。

我该怎么做? ColumnMappings的一些技巧?

修改

我接下来会这样做:

DataTable table = new DataTable();
using (var adapter = new SqlDataAdapter(sourceCommand))
{
    adapter.Fill(table);
}

table.Columns
    .OfType<DataColumn>()
    .ForEach(c => bulk.ColumnMappings.Add(
        new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)));

bulk.WriteToServer(table)

并获得:

  

给定的ColumnMapping与源或目标中的任何列都不匹配。

4 个答案:

答案 0 :(得分:16)

DataTable table = new DataTable();
using (var adapter = new SqlDataAdapter(sourceCommand))
{
    adapter.Fill(table);
}

using (SqlBulkCopy bulk = new SqlBulkCopy(targetConnection, SqlBulkCopyOptions.KeepIdentity, null) { DestinationTableName = tableName })
{
    foreach (string columnName in GetMapping(stringSource, stringTarget, tableName))
    {
        bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping(columnName, columnName));
    }

    targetConnection.Open();
    bulk.WriteToServer(table);
}

private static IEnumerable<string> GetMapping(string stringSource, string stringTarget, string tableName)
{
    return Enumerable.Intersect(
        GetSchema(stringSource, tableName),
        GetSchema(stringTarget, tableName),
        StringComparer.Ordinal); // or StringComparer.OrdinalIgnoreCase
}

private static IEnumerable<string> GetSchema(string connectionString, string tableName)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    using (SqlCommand command = connection.CreateCommand())
    {
        command.CommandText = "sp_Columns";
        command.CommandType = CommandType.StoredProcedure;

        command.Parameters.Add("@table_name", SqlDbType.NVarChar, 384).Value = tableName;

        connection.Open();
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                yield return (string)reader["column_name"];
            }
        }
    }
}

答案 1 :(得分:10)

使用SqlBulkCopyColumnMapping时,只会复制为其创建映射的列。

如果没有为列创建映射,则复制过程将忽略该映射。

您可以在演示代码here中看到这一点 - AdventureWorks演示数据库中的示例源表包含的列数多于映射或复制的列数。

修改

如果没有关于数据库模式的更多信息,很难确定,但是猜测问题出现在这个声明中:

new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)

根据您的描述,听起来并非源表中的所有列都存在于目标表中。您需要在SqlBulkCopyColumnMapping构造循环中使用过滤器来跳过目标中不存在的任何列。

我的C#不够好,不能给出一个我相信会有效的例子,但在伪代码中它会是

foreach column c in sourcetable
{
    if c.ColumnName exists in destination_table.columns
    {
          new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)
    }
}

(我确信可以将其转换为lambda表达式)

请注意,在列名匹配但数据类型不兼容的情况下,这不是特别健壮。

答案 2 :(得分:3)

Ed Harper,这就是没有伪代码的样子 (在本例中,从DataTable dt(完全定义)到db中的现有表:

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
{
    bulkCopy.DestinationTableName = "dbo.DepartmentsItems";

    // Write from the source to the destination.
    foreach (DataColumn c in dt.Columns)
    {
        bulkCopy.ColumnMappings.Add(c.ColumnName, c.ColumnName);
    }

    bulkCopy.WriteToServer(dt);
    return dt.Rows.Count;
}

答案 3 :(得分:1)

试试这个:SqlBulkCopyColumnMapping Class

希望您正在寻找相同的