2013-08-09 1 views
23

DataTable에서 SqlBulkCopy를 수행하려고 할 때이 예외가 발생합니다.SqlBulkCopy - 데이터 원본의 String 형식의 지정된 값을 지정된 대상 열의 money 형식으로 변환 할 수 없습니다.

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 자에게 전송 된 요청에 따라 다릅니다. 데이터 테이블 열은 모두 문자열 유형입니다.

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

이 코드는 목적지에 대한 모든 값을 포맷해야 내 데이터베이스의 열 전에 삽입을 실행에, 나는 다음과 같은 코드 (제거되지 않은 중요한 코드)를 사용하여 데이터 테이블 값을 포맷 따라서, 모든 VARCHAR 없습니다 전지. 십진수 오류가있는 경우이를 지우는 함수는 0-9 또는 0이 아닌 문자를 모두 제거합니다. (소수점). 오류를 던지고있는이 필드는 데이터베이스에서 Nullable이 될 수 있습니다.

수준이 예외는이 오류가 있습니다

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) 

누구도 해결하기 위해 어떤 아이디어가 있습니까 :

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 예외를이 오류가? 자세한 정보를 얻으려는 아이디어가 있습니까?

+1

문서를 보면 이벤트를 발생시키는 ['NotifyAfter'] (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.notifyafter.aspx) 속성을 사용할 수 있습니다. N 개의 행이 복사 될 때 기본 행이있는 행의 배치를 파악하는 데 도움이 될 수 있습니다. – shahkalpesh

+1

'CleanDecimal' 메소드가 데이터의 유효성 검사를 시도하거나 유효하지 않은 문자를 제거하려고합니까? 'Decimal.TryParse()'를 사용하여 데이터가 실제로 올바른 형식인지 확인해 보았습니까? 그에게 가서 문제가되는 가치가 나타나는지 확인하십시오. – Corey

답변

18

@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에 관해서 유사한 오류 메시지가 점점 사람들의

35

:

The given value of type String from the data source cannot be converted to type nvarchar of the specified target column.

이는 너무 짧은 컬럼에 의해 발생할 수 있습니다.

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

Source

22

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); 
       } 
      } 
     } 
    } 
} 
+2

질문의 코드 예제를 보면 ColumnMappings이 설정됩니다. 이것은 열을 매핑하는 것과 관련이 없으며 오히려 해당 열로 들어가는 데이터의 형식입니다. – Ricketts

+6

그들은 SqlBulkCopy가 이러한 열을 자동 매핑한다고 말하지만 실제로는 이러한 열을 지정해야합니다. 그렇지 않으면 이러한 유형의 오류가 발생합니다. 그것이 최소한 나를 위해 일한 것입니다. – Micro

+1

이전에 자동 매핑을 사용했지만 거의 120 열의 데이터 세트에서 bigint (varchar 대신)와 동일한 문제가 발생했습니다. 단순히 명시 적으로 열을 매핑하면 해결되었습니다. 그림을 이동. – DotThoughts

0

확인 당신이 서버에 작성하는 데이터입니다.사용할 수없는 구분 기호가있는 데이터 일 수 있습니다.

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

당신의 구분 기호 '|'이지만 데이터에는 구분 기호 ';'. 이렇게하면 오류가 발생합니다.

2

엔티티 클래스에 추가 된 열 값 u가 대상 테이블에있는 것과 동일한 순서로 set 속성을 가져야합니다.

+0

왜이 기능을 다운 그레이드 했습니까? 잘못된 열 순서로 인해이 예외가 발생했습니다. –

관련 문제