在SqlBulkCopy中跳过一些列

aba*_*hev 9 c# sql-server sqlbulkcopy sql-server-2008 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)
Run Code Online (Sandbox Code Playgroud)

得到:

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

aba*_*hev 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"];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ed *_*per 10

使用SqlBulkCopyColumnMapping时,仅复制为其创建映射的列.

如果不为列创建映射,则复制过程将忽略该映射.

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

编辑

如果没有关于数据库模式的更多信息,很难确定,但是猜测问题是这个语句:

new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)
Run Code Online (Sandbox Code Playgroud)

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

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

foreach column c in sourcetable
{
    if c.ColumnName exists in destination_table.columns
    {
          new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)
    }
}
Run Code Online (Sandbox Code Playgroud)

(我确定可以将它转换为lambda表达式)

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


小智 5

Ed Harper, this is what it looks like without pseudo code (in this case from DataTable dt (fully defined) to an existing table in the 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;
}
Run Code Online (Sandbox Code Playgroud)