SqlBulkCopy - 데이터 소스의 String 유형의 지정된 값을 지정된 대상 열의 money 유형으로 변환 할 수 없습니다.

c# datatable sqlbulkcopy

문제

DataTable에서 SqlBulkCopy를 할 때이 예외가 발생합니다.

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)

오류의 의미를 이해하지만 어떻게 행 / 필드와 같은 더 많은 정보를 얻을 수 있습니까? 데이터 테이블은 타사에서 채워지며 최대 200 개의 열과 최대 10,000 개의 행을 포함 할 수 있습니다. 반환되는 열은 제 3 자에게 전송 된 요청에 따라 다릅니다. 모든 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'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
}

이 코드는 대상 필드의 모든 값을 형식화해야합니다. 십진수 오류가있는 경우이를 지우는 함수는 0-9 또는 0이 아닌 문자를 모두 제거합니다. (소수점). 오류를 던지고있는이 필드는 데이터베이스에서 Nullable이 될 수 있습니다.

수준 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)

누구든지 고칠 수있는 아이디어가 있습니까? 자세한 정보를 얻으려는 아이디어가 있습니까?

수락 된 답변

@ 코리 (Corey) - 모든 잘못된 문자를 제거합니다. 그러나 귀하의 의견은 저에게 답을 생각하게했습니다.

문제는 내 데이터베이스의 많은 필드가 null 가능하다는 것입니다. SqlBulkCopy를 사용하면 빈 문자열이 Null 값으로 삽입되지 않습니다. 따라서 varchar (bit, 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());
}

위의 조정을 한 후에 모든 것이 문제없이 삽입됩니다.


인기 답변

이 질문을 가로막는 사람들에게 돈 대신에 nvarchar와 관련하여 비슷한 오류 메시지가 나타나는 경우

데이터 소스의 String 유형에 지정된 값을 지정된 대상 열의 nvarchar 유형으로 변환 할 수 없습니다.

이것은 너무 짧은 열로 인해 발생할 수 있습니다.

예를 들어 열이 nvarchar(20) 로 정의되어 있고 40 자 문자열이 있으면이 오류가 발생할 수 있습니다.

출처



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.