2011-08-23 12 views
14

Sono in procinto di convertire alcune routine di reporting basate su stored procedure da eseguire in C#. L'idea generale è quella di utilizzare tutte le meraviglie di C# /. NET Framework e quindi restituire i risultati nel DB. Tutto è andato a gonfie vele, tranne per un problema che ho incontrato ieri e risolto oggi.Ottenere SqlBulkCopy per onorare i nomi delle colonne

Per eseguire l'importazione, sto creando un DataTable al livello di programmazione e utilizzando SqlBulkCopy per spostare i risultati sul server.

ad es.

DataTable detail = new DataTable(); 
detail.Columns.Add(new DataColumn("Stock", Type.GetType("System.Decimal"))); 
detail.Columns.Add(new DataColumn("Receipts", Type.GetType("System.Decimal"))); 
detail.Columns.Add(new DataColumn("Orders", Type.GetType("System.Decimal"))); 

La tabella di importazione contiene i campi nel seguente ordine.

... 
Stock decimal(18,4), 
Orders decimal(18,4), 
Receipts decimal(18,4) 
... 

In sostanza, il valore per Receipts stava entrando in ordini e viceversa.

Evidentemente, questo è dovuto al fatto che SqlBulkCopy non sembra rispettare il nome della colonna che gli ho detto di compilare, ma solo per posizione ordinale.

Questo è un problema per me poiché utilizziamo il confronto SQL di Redgate. Quando si spostano le modifiche da un database a un altro, la posizione ordinale delle colonne non viene necessariamente mantenuta. Ad esempio, se si inserisce una nuova colonna come terzo campo ordinale, SQL Compare lo aggiungerà alla tabella solo su una sincronizzazione, rendendola l'ultima colonna.

Questo compromette seriamente la mia soluzione. Ora, queste sono solo tabelle di "importazione", quindi se necessario, posso rilasciarle e ricrearle come parte di qualsiasi script di migrazione con le posizioni ordinali intatte. Preferirei non farlo comunque.

C'è un modo per forzare SqlBulkCopy ad onorare i nomi delle colonne che gli dici di riempire?

+0

P.S., c'è un'opzione di progetto in Red Gate SQL Compare denominata "Ordine colonna forzata" che manterrà l'ordine delle colonne lo stesso durante le sincronizzazioni di nuove colonne. (Intendiamoci, questo richiede una goccia e la ricostruzione del tavolo, ma ha funzionato bene per me in passato quando assolutamente necessario.) – Funka

risposta

14

Da http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.columnmappings.aspx:

Tuttavia, se la conta delle colonne differiscono, o le posizioni ordinali non sono coerenti, è necessario utilizzare ColumnMappings per assicurarsi che i dati vengano copiati nelle colonne corrette.

Per codice di esempio si veda "Colonne Mapping" a http://www.sqlteam.com/article/use-sqlbulkcopy-to-quickly-load-data-from-your-client-to-sql-server

+0

Esattamente ciò di cui avevo bisogno. Grazie. –

+0

la mia risposta qui sotto risolve il problema dell'ordine .. :) – ttomsen

+0

eccetto quello che voglio (differenza del conteggio delle colonne) –

0

Esistono sovraccarichi che consentono di specificare la posizione ordinale o il nome della colonna di origine da mappare alla colonna di destinazione.

Verificare SqlBulkCopyColumnMappingCollection.Add e impostare la proprietà .

0

potrei mancare qualcosa, ma perché non hai potuto cambiare l'ordine delle colonne? Di solito non costruisco il mio DataTable a mano. Io uso il metodo FillSchema di SqlDataAdapter, utilizzando una query "select * from targetTable". Quindi sono sempre sicuro che il mio DataTable si adatta alla tabella di destinazione.

1

C'è un'opzione in SQL Compare per forzare l'ordine delle colonne nelle opzioni del progetto. Questo genererà uno script che riordina le colonne. Potrei sbagliarmi, ma penso che questa operazione potrebbe richiedere la ricostruzione della tabella, quindi si prega di usare con cautela in quanto ciò potrebbe influenzare le prestazioni. Lo script, tuttavia, conserva i dati della tabella.

9

Ecco una soluzione per risolvere questo "bug".

Il valore predefinito è mappare per ordinale/posizione.

Nel mio caso stavo caricando da un foglio elettronico con colonne in ordine casuale. ecco una soluzione rapida (tabella è il mio DataTable che è 'fuori uso ordinale', e bulkcopy è l'oggetto SqlBulkCopy)

foreach (DataColumn col in table.Columns) 
{ 
    bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName); 
} 

Come potete vedere, sto solo costringendolo a ri-ordinare per nome, anche se i nomi sono IDENTICI.

+0

Questo mi ha salvato un paio d'ore! Grazie molto... –

Problemi correlati