SqlBulkCopy - Il valore dato di tipo String dall'origine dati non può essere convertito in tipo money della colonna di destinazione specificata

c# datatable sqlbulkcopy

Domanda

Sto ottenendo questa eccezione quando provo a fare un SqlBulkCopy da un DataTable.

Error Message: The given value of type String from the data source cannot be converted to type money of the specified target column.
Target Site: System.Object ConvertValue(System.Object, System.Data.SqlClient._SqlMetaData, Boolean, Boolean ByRef, Boolean ByRef)

Capisco cosa sta dicendo l'errore, ma come posso ottenere più informazioni, come la riga / campo su cui si sta verificando? Il datatable è popolato da una terza parte e può contenere fino a 200 colonne e fino a 10k righe. Le colonne restituite dipendono dalla richiesta inviata alla terza parte. Tutte le colonne datatable sono di tipo stringa. Le colonne nel mio database non sono tutte varchar, quindi, prima dell'esecuzione dell'inserto, formatto i valori datatable usando il seguente codice (codice non importante rimosso):

//--- create lists to hold the special data type columns
List<DataColumn> IntColumns = new List<DataColumn>();
List<DataColumn> DecimalColumns = new List<DataColumn>();
List<DataColumn> BoolColumns = new List<DataColumn>();
List<DataColumn> DateColumns = new List<DataColumn>();

foreach (DataColumn Column in dtData.Columns)
{
    //--- find the field map that tells the system where to put this piece of data from the 3rd party
    FieldMap ColumnMap = AllFieldMaps.Find(a => a.SourceFieldID.ToLower() == Column.ColumnName.ToLower());

    //--- get the datatype for this field in our system
    Type FieldDataType = Nullable.GetUnderlyingType(DestinationType.Property(ColumnMap.DestinationFieldName).PropertyType);

    //--- find the field data type and add to respective list
    switch (Type.GetTypeCode(FieldDataType))
    {
        case TypeCode.Int16:
        case TypeCode.Int32:
        case TypeCode.Int64: { IntColumns.Add(Column); break; }
        case TypeCode.Boolean: { BoolColumns.Add(Column); break; }
        case TypeCode.Double:
        case TypeCode.Decimal: { DecimalColumns.Add(Column); break; }
        case TypeCode.DateTime: { DateColumns.Add(Column); break; }
    }

    //--- add the mapping for the column on the BulkCopy object
    BulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(Column.ColumnName, ColumnMap.DestinationFieldName));
}

//--- loop through all rows and convert the values to data types that match our database's data type for that field
foreach (DataRow dr in dtData.Rows)
{
    //--- convert int values
    foreach (DataColumn IntCol in IntColumns)
        dr[IntCol] = Helpers.CleanNum(dr[IntCol].ToString());

    //--- convert decimal values
    foreach (DataColumn DecCol in DecimalColumns)
        dr[DecCol] = Helpers.CleanDecimal(dr[DecCol].ToString());

    //--- convert bool values
    foreach (DataColumn BoolCol in BoolColumns)
        dr[BoolCol] = Helpers.ConvertStringToBool(dr[BoolCol].ToString());

    //--- convert date values
    foreach (DataColumn DateCol in DateColumns)
        dr[DateCol] = dr[DateCol].ToString().Replace("T", " ");
}

try
{
    //--- do bulk insert
    BulkCopy.WriteToServer(dtData);
    transaction.Commit();
}
catch (Exception ex)
{
    transaction.Rollback();

    //--- handles error
    //--- this is where I need to find the row & column having an issue
}

Questo codice dovrebbe formattare tutti i valori per i loro campi di destinazione. Nel caso di questo errore, il decimale, la funzione che pulisce quello rimuoverà qualsiasi carattere che non sia 0-9 o. (punto decimale). Questo campo che genera l'errore potrebbe essere annullabile nel database.

L'eccezione di livello 2 ha questo errore:

Error Message: Failed to convert parameter value from a String to a Decimal.
Target Site: System.Object CoerceValue(System.Object, System.Data.SqlClient.MetaType, Boolean ByRef, Boolean ByRef, Boolean)

e l'eccezione di livello 3 ha questo errore:

Error Message: Input string was not in a correct format
Target Site: Void StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)

Qualcuno ha qualche idea da risolvere? o qualche idea per avere maggiori informazioni?

Risposta accettata

@Corey: semplicemente rimuove tutti i caratteri non validi. Tuttavia, il tuo commento mi ha fatto pensare alla risposta.

Il problema era che molti dei campi nel mio database sono annullabili. Quando si utilizza SqlBulkCopy, una stringa vuota non viene inserita come valore null. Quindi, nel caso dei miei campi che non sono varchar (bit, int, decimal, datetime, ecc.) Cercava di inserire una stringa vuota, che ovviamente non è valida per quel tipo di dati.

La soluzione era di modificare il mio ciclo in cui convalidare i valori a questo (ripetuto per ogni tipo di dati che non è una stringa)

//--- convert decimal values
foreach (DataColumn DecCol in DecimalColumns)
{
     if(string.IsNullOrEmpty(dr[DecCol].ToString()))
          dr[DecCol] = null; //--- this had to be set to null, not empty
     else
          dr[DecCol] = Helpers.CleanDecimal(dr[DecCol].ToString());
}

Dopo aver apportato le modifiche sopra, tutto si inserisce senza problemi.


Risposta popolare

Per le persone che incappano in questa domanda e ricevono un messaggio di errore simile riguardo a un nvarchar invece di soldi:

Il valore dato di tipo String dall'origine dati non può essere convertito in tipo nvarchar della colonna di destinazione specificata.

Questo potrebbe essere causato da una colonna troppo breve.

Ad esempio, se la tua colonna è definita come nvarchar(20) e hai una stringa di 40 caratteri, potresti ricevere questo errore.

fonte



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é