SqlBulkCopy - La valeur donnée de type String de la source de données ne peut pas être convertie en type money de la colonne cible spécifiée

c# datatable sqlbulkcopy

Question

Je reçois cette exception lorsque j'essaie de créer une SqlBulkCopy à partir d'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)

Je comprends ce que dit l'erreur, mais comment puis-je obtenir plus d'informations, telles que la ligne / le champ concerné? Le datatable est peuplé par une tierce partie et peut contenir jusqu'à 200 colonnes et 10 000 lignes. Les colonnes renvoyées dépendent de la demande envoyée à la 3ème partie. Toutes les colonnes datatable sont de type chaîne. Les colonnes de ma base de données ne sont pas toutes varchar. Par conséquent, avant d'exécuter l'insertion, je formate les valeurs datatable à l'aide du code suivant (code non important supprimé):

//--- 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
}

Ce code doit formater toutes les valeurs pour leurs champs de destination. Dans le cas de cette erreur, la décimale, la fonction qui nettoie supprimera tout caractère autre que 0-9 ou. (virgule). Ce champ qui génère l'erreur serait nullable dans la base de données.

L'exception de niveau 2 a cette erreur:

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)

et l'exception de niveau 3 a cette erreur:

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)

Est-ce que quelqu'un a des idées à résoudre? ou des idées pour obtenir plus d'informations?

Réponse acceptée

@Corey - Il supprime simplement tous les caractères non valides. Cependant, votre commentaire m'a fait penser à la réponse.

Le problème était que beaucoup de champs de ma base de données sont nuls. Lors de l'utilisation de SqlBulkCopy, une chaîne vide n'est pas insérée en tant que valeur null. Ainsi, dans le cas de mes champs qui ne sont pas varchar (bits, entiers, décimaux, date / heure, etc.), il essayait d'insérer une chaîne vide, ce qui n'est évidemment pas valide pour ce type de données.

La solution a été de modifier ma boucle où je valide les valeurs (répétée pour chaque type de données qui n'est pas une chaîne)

//--- 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());
}

Après avoir effectué les réglages ci-dessus, tout est inséré sans problème.


Réponse populaire

Pour les personnes qui tombent sur cette question et reçoivent un message d'erreur similaire en ce qui concerne un nvarchar au lieu d'argent:

La valeur donnée de type String de la source de données ne peut pas être convertie en type nvarchar de la colonne cible spécifiée.

Cela pourrait être causé par une colonne trop courte.

Par exemple, si votre colonne est définie comme nvarchar(20) et que vous avez une chaîne de 40 caractères, vous pouvez obtenir cette erreur.

La source



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi