13

我正在使用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

4 回答 4

19
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"];
            }
        }
    }
}
于 2010-09-24T09:22:02.310 回答
13

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

如果您不为列创建映射,则复制过程将忽略它。

您可以在此处的演示代码中看到这一点- 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 表达式)

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

于 2010-09-24T07:51:51.830 回答
5

Ed Harper,这就是没有伪代码的样子(在这种情况下,从 DataTable dt(完全定义)到数据库中的现有表:

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;
}
于 2017-09-18T12:32:57.243 回答
1

试试这个:SqlBulkCopyColumnMapping 类

希望你正在寻找相同的

于 2010-09-24T07:18:19.973 回答