Campo calculado de SqlBulkCopy

.net c# ms-access sqlbulkcopy sql-server

Pregunta

Estoy trabajando para mover una base de datos de MS Access al servidor SQL. Para mover los datos a las nuevas tablas, he decidido escribir una rutina de sincronización, ya que el esquema ha cambiado significativamente y me permite ejecutar pruebas en programas que se ejecutan y volver a sincronizar cada vez que necesito nuevos datos de prueba. Luego, finalmente haré una última sincronización y comenzaré en vivo en la nueva versión del servidor SQL.

Desafortunadamente, tengo un problema, mi método está abajo para copiar desde Access a SQLServer

public static void BulkCopyAccessToSQLServer
        (string sql, CommandType commandType, DBConnection sqlServerConnection,
            string destinationTable, DBConnection accessConnection, int timeout)
    {
        using (DataTable dt = new DataTable())
        using (OleDbConnection conn = new OleDbConnection(GetConnection(accessConnection)))
        using (OleDbCommand cmd = new OleDbCommand(sql, conn))
        using (OleDbDataAdapter adapter = new OleDbDataAdapter(cmd))
        {
            cmd.CommandType = commandType;
            cmd.Connection.Open();
            adapter.SelectCommand.CommandTimeout = timeout;
            adapter.Fill(dt);

            using (SqlConnection conn2 = new SqlConnection(GetConnection(sqlServerConnection)))
            using (SqlBulkCopy copy = new SqlBulkCopy(conn2))
            {
                conn2.Open();

                copy.DestinationTableName = destinationTable;
                copy.BatchSize = 1000;
                copy.BulkCopyTimeout = timeout;
                copy.WriteToServer(dt);
                copy.NotifyAfter = 1000;
            }
        }
    }

Básicamente, este acceso de consultas para los datos mediante la cadena de entrada sql tiene todos los nombres de campo correctos, por lo que no es necesario configurar las columnas.

Esto funcionó hasta que llegué a una tabla con un campo calculado. Parece que SQLBulkCopy no omite el campo e intenta actualizar la columna que falla con el error "La columna 'columnName' no se puede modificar porque es una columna computada o es el resultado de un operador de unión".

¿Hay una manera fácil de hacerlo omitir el campo calculado?

Espero no tener que especificar una asignación de columna completa.

Respuesta aceptada

Hay dos maneras de esquivar esto:

  • use ColumnMappings para definir formalmente la relación de columna (nota que no quiere esto)
  • inserte los datos en una tabla de preparación : una tabla básica, que no forma parte de sus tablas transaccionales principales, cuyo propósito es lucir exactamente como esta importación de datos; luego use un comando TSQL para transferir los datos de la tabla de etapas a la tabla real

Siempre prefiero la segunda opción, por varias razones:

  • Nunca tengo que meterme con las asignaciones, esto es realmente importante para mí;
  • la inserción en la tabla real se registrará completamente ( SqlBulkCopy no necesariamente se registra)
  • Tengo el inserto más rápido posible: sin verificación de restricciones, sin indexación, etc.
  • No vinculo una tabla transaccional durante la importación y no hay riesgo de que las consultas no repetibles se ejecuten en una tabla parcialmente importada
  • Tengo una opción de cancelación segura si la importación falla a la mitad, sin tener que usar transacciones (nada ha tocado el sistema transaccional en este punto)
  • permite cierto nivel de procesamiento de datos al insertarlo en las tablas reales, sin la necesidad de almacenar todo en un DataTable en el nivel de la aplicación o implementar un IDataReader personalizado


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é