2013-08-09 24 views
23

DataTableからSqlBulkCopyを実行しようとすると、この例外が発生します。SqlBulkCopy - データソースのString型の指定された値を、指定された対象列の型に変換できません。

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の列と最大10kの行を含むことができます。返される列は、第三者に送信された要求によって異なります。 datatableの列はすべて文字列型です。このコードは、その先のすべての値をフォーマットする必要があります

//--- 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以外の文字を削除します。 (小数点)。エラーをスローしているこのフィールドは、データベースで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) 

誰でも修正する任意のアイデアを持っていますか?またはより多くの情報を得るためのアイデア?

+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ではなく)で同じ問題が発生しました。列を明示的にマッピングするだけで解決しました。 Go figure。 – DotThoughts

0

は、あなたがサーバーに書いているデータを確認してください。デリミタが使用されていないデータが使用されている可能性があります。

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

あなたの区切り文字です'|'ですが、データにはデリミタがあります';'。 これはエラーです。

2

エンティティクラスに追加された列の値uが、ターゲットテーブルに存在する順序と同じ順序でプロパティを取得することを確認します。

+0

なぜこれがダウン表示されましたか?列の順序が間違っているため、この例外の問題が発生しました。 –

関連する問題