Salta alcune colonne in SqlBulkCopy

c# columnmappings sqlbulkcopy sql-server sql-server-2008

Domanda

Sto usando SqlBulkCopy contro due SQL Server 2008 con diversi set di colonne (andando a spostare alcuni dati da prod server a dev ). Quindi, vuoi saltare alcune colonne non ancora esistenti / non ancora rimosse.

Come lo posso fare? Qualche trucco con ColumnMappings ?

Modificare:

Io faccio il prossimo:

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)

e prendi:

Il dato ColumnMapping non corrisponde a nessuna colonna nell'origine o nella destinazione.

Risposta accettata

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"];
            }
        }
    }
}

Risposta popolare

Quando si utilizza SqlBulkCopyColumnMapping, verranno copiate solo le colonne per cui sono stati creati i mapping.

Se non si crea una mappatura per una colonna, questa verrà ignorata dal processo di copia.

Puoi vedere questo nel codice demo qui : la tabella di esempio nel database demo di AdventureWorks contiene più colonne di quelle che sono mappate o copiate.

MODIFICARE

È difficile essere certi senza ulteriori informazioni sullo schema del database, ma a un certo punto il problema è con questa affermazione:

new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)

Dalla tua descrizione, sembra che non tutte le colonne nella tabella di origine esistano nella tabella di destinazione. È necessario un filtro nel ciclo di costruzione SqlBulkCopyColumnMapping per saltare le colonne che non esistono nella destinazione.

La mia C # non è abbastanza buona per dare un esempio che sono sicuro che funzionerà, ma in pseudocodice sarebbe

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

(Sono sicuro che è possibile convertire questo in un'espressione lambda)

Si noti che questo non è particolarmente robusto nello scenario in cui i nomi delle colonne corrispondono ma i tipi di dati non sono compatibili.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow