13

SqlBulkCopy異なる列のセットを持つ2つのSQLServer2008に対して使用しています(一部のデータを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)
    }
}

(これをラムダ式に変換できると確信しています)

これは、列名は一致するがデータ型に互換性がないシナリオでは特に堅牢ではないことに注意してください。

于 2010-09-24T07:51:51.830 に答える
5

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

これを試してください:SqlBulkCopyColumnMappingクラス

あなたが同じものを探していることを願っています

于 2010-09-24T07:18:19.973 に答える