Campo calcolato SqlBulkCopy

.net c# ms-access sqlbulkcopy sql-server

Domanda

Sto lavorando per spostare un database da MS Access a SQL Server. Per spostare i dati nelle nuove tabelle, ho deciso di scrivere una routine di sincronizzazione poiché lo schema è cambiato in modo significativo e mi consente di eseguire test sui programmi che eseguono il riavvio e la risincronizzazione ogni volta che ho bisogno di nuovi dati di test. Quindi alla fine eseguirò un'ultima sincronizzazione e avvierò la diretta sulla nuova versione del server sql.

Sfortunatamente ho colpito un ostacolo, il mio metodo è sotto per copiare da 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;
            }
        }
    }

Fondamentalmente questa query accede ai dati usando la stringa sql di input, questo ha tutti i nomi di campo corretti, quindi non ho bisogno di impostare columnmappings.

Questo funzionava finché non raggiunsi un tavolo con un campo calcolato. SQLBulkCopy sembra non sapere di saltare il campo e tenta di aggiornare la colonna che fallisce con l'errore "La colonna 'columnName' non può essere modificata perché è una colonna calcolata o è il risultato di un operatore di unione."

C'è un modo semplice per farlo saltare il campo calcolato?

Spero di non dover specificare una mappatura completa della colonna.

Risposta accettata

Ci sono due modi per evitare questo:

  • utilizzare ColumnMappings per definire formalmente la relazione tra le colonne (si noti che non si desidera questo)
  • spingere i dati in una tabella di staging , una tabella di base, non parte delle tabelle transazionali principali, il cui unico scopo è di assomigliare esattamente a questa importazione di dati; quindi utilizzare un comando TSQL per trasferire i dati dalla tabella di staging alla tabella reale

Sono sempre favorevole alla seconda opzione, per vari motivi:

  • Non devo mai scherzare con le mappature - questo è davvero importante per me, p
  • l'inserto nella tabella reale verrà completamente registrato ( SqlBulkCopy non è necessariamente registrato)
  • Ho l'inserto più veloce possibile: nessun controllo dei vincoli, nessuna indicizzazione, ecc
  • Non lego una tabella transazionale durante l'importazione e non vi è alcun rischio di query non ripetibili eseguite su una tabella parzialmente importata
  • Ho un'opzione di annullamento sicuro se l'importazione fallisce a metà, senza dover utilizzare le transazioni (nulla ha toccato il sistema transazionale a questo punto)
  • consente un certo livello di elaborazione dei dati quando lo si inserisce nelle tabelle reali, senza la necessità di bufferizzare tutto in un DataTable al livello dell'app, o implementare un IDataReader personalizzato


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché