Ignorer des colonnes dans SqlBulkCopy

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

Question

J'utilise SqlBulkCopy contre deux SQL Server 2008 avec différents ensembles de colonnes (va déplacer des données de prod serveur dev ). Donc, voulez sauter certaines colonnes qui n'existaient pas encore / qui n'ont pas encore été supprimées.

Comment puis je faire ça? Un truc avec ColumnMappings ?

Modifier:

Je fais ensuite:

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)

et obtenir:

Le ColumnMapping donné ne correspond à aucune colonne de la source ou de la destination.

Réponse acceptée

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

Réponse populaire

Lorsque SqlBulkCopyColumnMapping est utilisé, seules les colonnes pour lesquelles des mappages sont créés seront copiées.

Si vous ne créez pas de mappage pour une colonne, celle-ci sera ignorée par le processus de copie.

Vous pouvez le voir dans le code de démonstration ici - la table source exemple de la base de données de démonstration AdventureWorks contient plus de colonnes que celles mappées ou copiées.

MODIFIER

Il est difficile d'être certain sans plus d'informations sur le schéma de la base de données, mais le problème est lié à cette déclaration:

new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)

D'après votre description, il semble que toutes les colonnes de la table source n'existent pas dans la table de destination. Vous avez besoin d'un filtre dans votre boucle de construction SqlBulkCopyColumnMapping pour ignorer les colonnes qui n'existent pas dans la destination.

Mon C # n'est pas assez bon pour donner un exemple qui, j'en suis sûr, fonctionnera, mais en pseudocode, ce serait

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

(Je suis sûr qu'il est possible de convertir cela en une expression lambda)

Notez que cela n’est pas particulièrement robuste dans le cas où les noms de colonnes correspondent mais que les types de données sont incompatibles.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi