Saltar algunas columnas en SqlBulkCopy

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

Pregunta

Estoy usando SqlBulkCopy contra dos SQL Server 2008 con diferentes conjuntos de columnas (voy a mover algunos datos del servidor prod al dev ). Así que quiero omitir algunas columnas que aún no existían / ​​aún no se han eliminado.

¿Cómo puedo hacer eso? ¿Algún truco con ColumnMappings ?

Editar:

Hago lo siguiente

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)

y obten:

El ColumnMapping dado no coincide con ninguna columna en el origen o destino.

Respuesta aceptada

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

Respuesta popular

Cuando se usa SqlBulkCopyColumnMapping, solo se copiarán las columnas para las cuales se crean las asignaciones.

Si no crea una asignación para una columna, el proceso de copia lo ignorará.

Puede ver esto en el código de demostración aquí : la tabla de origen de muestra en la base de datos de demostración de AdventureWorks contiene más columnas de las que están asignadas o copiadas.

EDITAR

Es difícil estar seguro sin más información sobre el esquema de la base de datos, pero supongo que el problema está en esta declaración:

new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)

Según su descripción, parece que no todas las columnas de la tabla de origen existen en la tabla de destino. Necesita un filtro en su SqlBulkCopyColumnMapping construcción SqlBulkCopyColumnMapping para omitir cualquier columna que no exista en el destino.

Mi C # no es lo suficientemente bueno para dar un ejemplo que estoy seguro de que funcionará, pero en pseudocódigo sería

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

(Estoy seguro de que es posible convertir esto en una expresión lambda)

Tenga en cuenta que esto no es particularmente sólido en el escenario donde los nombres de las columnas coinciden, pero los tipos de datos son incompatibles.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué