Подтвердить что ты не робот

SqlBulkCopy - заданное значение типа String из источника данных не может быть преобразовано в тип денег указанного целевого столбца

Я получаю это исключение, когда пытаюсь выполнить SqlBulkCopy из 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)

Я понимаю, что говорит ошибка, но как я могу получить дополнительную информацию, например строку/поле, на котором это происходит? Данные datatable заполняются третьей стороной и могут содержать до 200 столбцов и до 10 тыс. Строк. Возвращаемые столбцы зависят от запроса, отправленного третьей стороне. Все столбцы datatable имеют строковый тип. Поэтому столбцы в моей базе данных не все varchar, поэтому перед выполнением вставки я отформатирую данные, используя следующий код (не важный код удален):

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

Этот код должен форматировать все значения для своих целевых полей. В случае этой ошибки десятичная функция, которая очищает это, удалит любой символ, который не равен 0-9 или. (десятичная точка). Это поле, которое бросает ошибку, будет иметь значение NULL в базе данных.

Исключение уровня 2 имеет эту ошибку:

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)

и исключение уровня 3 имеет эту ошибку:

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)

Есть ли у кого-нибудь идеи исправить? или какие-либо идеи для получения дополнительной информации?

4b9b3361

Ответ 1

@Corey - он просто удаляет все недопустимые символы. Однако ваш комментарий заставил меня задуматься над ответом.

Проблема заключалась в том, что многие поля в моей базе данных имеют значение NULL. При использовании SqlBulkCopy пустая строка не вводится как нулевое значение. Поэтому в случае моих полей, которые не являются varchar (бит, int, decimal, datetime и т.д.), Он пытался вставить пустую строку, которая явно не подходит для этого типа данных.

Решением было изменить мой цикл, где я проверяю значения на это (повторяется для каждого типа данных, который не является строкой)

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

После внесения изменений выше все вставляет без проблем.

Ответ 2

Для людей, которые спотыкаются об этом вопросе и получают подобное сообщение об ошибке в отношении nvarchar вместо денег:

Данное значение типа String из источника данных не может быть преобразовано в тип nvarchar указанного целевого столбца.

Это может быть вызвано слишком коротким столбцом.

Например, если ваш столбец определяется как nvarchar(20) и у вас есть строка с 40 символами, вы можете получить эту ошибку.

Источник

Ответ 3

Пожалуйста, используйте SqlBulkCopyColumnMapping.

Пример:

private void SaveFileToDatabase(string filePath)
{
    string strConnection = System.Configuration.ConfigurationManager.ConnectionStrings["MHMRA_TexMedEvsConnectionString"].ConnectionString.ToString();

    String excelConnString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0\"", filePath);
    //Create Connection to Excel work book 
    using (OleDbConnection excelConnection = new OleDbConnection(excelConnString))
    {
        //Create OleDbCommand to fetch data from Excel 
        using (OleDbCommand cmd = new OleDbCommand("Select * from [Crosswalk$]", excelConnection))
        {
            excelConnection.Open();
            using (OleDbDataReader dReader = cmd.ExecuteReader())
            {
                using (SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection))
                {
                    //Give your Destination table name 
                    sqlBulk.DestinationTableName = "PaySrcCrosswalk";

                    SqlBulkCopyColumnMapping AdmissionPaySrcID=new SqlBulkCopyColumnMapping("AdmissionPaySrcID","AdmissionPaySrcID");
                    sqlBulk.ColumnMappings.Add(AdmissionPaySrcID);

                    SqlBulkCopyColumnMapping TMHP_Detail = new SqlBulkCopyColumnMapping("TMHP_Detail", "TMHP_Detail");
                    sqlBulk.ColumnMappings.Add(TMHP_Detail);

                    SqlBulkCopyColumnMapping PaySrcType = new SqlBulkCopyColumnMapping("PaySrcType", "PaySrcType");
                    sqlBulk.ColumnMappings.Add(PaySrcType);

                    SqlBulkCopyColumnMapping AgencyID = new SqlBulkCopyColumnMapping("AgencyID", "AgencyID");
                    sqlBulk.ColumnMappings.Add(AgencyID);

                    SqlBulkCopyColumnMapping CountyCode = new SqlBulkCopyColumnMapping("CountyCode", "CountyCode");
                    sqlBulk.ColumnMappings.Add(CountyCode);

                    SqlBulkCopyColumnMapping EntityID = new SqlBulkCopyColumnMapping("EntityID", "EntityID");
                    sqlBulk.ColumnMappings.Add(EntityID);

                    sqlBulk.WriteToServer(dReader);
                }
            }
        }
    }
}  

Ответ 4

Убедитесь, что значения столбца u, добавленные в класс сущностей, также имеют заданные свойства в том же порядке, который присутствует в целевой таблице.

Ответ 5

Проверьте данные, которые вы пишете на сервере. Может быть, у данных есть разделитель, который не используется.

like

045|2272575|0.000|0.000|2013-10-07
045|2272585|0.000|0.000;2013-10-07

ваш разделитель '|', но данные имеют разделитель ';'. Поэтому для этого вы получаете ошибку.