2017-06-08 24 views
1

ObjectReader(FastMember)でSqlBulkCopy(.NET)を使用してXMLベースのファイルからインポートを実行しています。私は適切な列のマッピングを追加しました。SqlBulkCopy with ObjectReader - Stringの値をInt32に変換できません

エラーが発生する場合があります。パラメータ値を文字列からInt32に変換できませんでした。

私は 2.失敗した実際のテーブルの列がObjectReader

サンプルコードの「現在」を入手する方法に 1.トレースを理解したいと思います:

 using (ObjectReader reader = genericReader.GetReader()) 
       { 
        try 
        { 
         sbc.WriteToServer(reader); //sbc is SqlBulkCopy instance 
         transaction.Commit(); 
        } 
        catch (Exception ex) 
        { 
         transaction.Rollback();       
        } 
       } 

はい"EX" そしてちょうどエラーの詳細情報を運ぶ:
System.InvalidOperationException : The given value of type String from the data source cannot be converted to type int of the specified target column.

答えて

0

単純な答えを

簡単な答えはノーです。​​が非常に高速な理由の1つは、何もログに記録しないということです。​​例外から追加の情報を直接取得することはできません。しかし、David Catrielはこれについての記事を書いており、hereについて完全に読むことができる可能な解決策を提供しています。

答えが得られるかもしれませんが、コード内で一貫して実行するとパフォーマンスに影響を及ぼす可能性があるため、デバッグ時にのみヘルパーメソッドを使用することをお勧めします。沿って、SqlBulkCopyは、すべての犯人のデータ行を

  • レポートに遭遇するであろうと

    1. レポートにすべての可能なエラーを:

      はなぜ

      The lack of logging definitely speeds things up, but when you are pumping hundreds of thousands of rows and suddenly have a failure on one of them because of a constraint, you're stuck. All the SqlException will tell you is that something went wrong with a given constraint (you'll get the constraint's name at least), but that's about it. You're then stuck having to go back to your source, run separate SELECT statements on it (or do manual searches), and find the culprit rows on your own.

      On top of that, it can be a very long and iterative process if you've got data with several potential failures in it because SqlBulkCopy will stop as soon as the first failure is hit. Once you correct that one, you need to rerun the load to find the second error, etc.

      利点を回避するを使用してください例外的に行が原因となっている可能性があります

    2. 全体が最後にロールバックされるトランザクションで実行されるため、変更はコミットされません。

    短所:

    1. は、大量のデータのために、それは数分かかる場合があります。

    2. この溶液は反応性である。つまり、エラーはSqlBulkCopy.WriteToServer()プロセスによって発生した例外の一部として返されません。代わりに、このヘルパーメソッドは、例外が発生して関連するデータと共にすべての考えられるエラーを取得しようとした後に実行されます。つまり、例外が発生した場合、バルク・コピーを実行するだけでなく、実行に時間がかかります。

    3. 読み取り不能の転送専用ホースはリセットできないため、失敗したSqlBulkCopyと同じDataReaderオブジェクトを再利用することはできません。同じタイプの新しいリーダーを作成する必要があります(元のSqlCommandを再発行する、同じDataTableに基づいてリーダーを再作成するなど)。

    GetBulkCopyFailedData方法 GetBulkCopyFailedData方法

    private void TestMethod() 
    { 
        // new code 
        SqlConnection connection = null; 
        SqlBulkCopy bulkCopy = null; 
    
        DataTable dataTable = new DataTable(); 
        // load some sample data into the DataTable 
        IDataReader reader = dataTable.CreateDataReader(); 
    
        try 
        { 
         connection = new SqlConnection("connection string goes here ..."); 
         connection.Open(); 
         bulkCopy = new SqlBulkCopy(connection); 
         bulkCopy.DestinationTableName = "Destination table name"; 
         bulkCopy.WriteToServer(reader); 
        } 
        catch (Exception exception) 
        { 
         // loop through all inner exceptions to see if any relate to a constraint failure 
         bool dataExceptionFound = false; 
         Exception tmpException = exception; 
         while (tmpException != null) 
         { 
         if (tmpException is SqlException 
          && tmpException.Message.Contains("constraint")) 
         { 
          dataExceptionFound = true; 
          break; 
         } 
         tmpException = tmpException.InnerException; 
         } 
    
         if (dataExceptionFound) 
         { 
         // call the helper method to document the errors and invalid data 
         string errorMessage = GetBulkCopyFailedData(
          connection.ConnectionString, 
          bulkCopy.DestinationTableName, 
          dataTable.CreateDataReader()); 
         throw new Exception(errorMessage, exception); 
         } 
        } 
        finally 
        { 
         if (connection != null && connection.State == ConnectionState.Open) 
         { 
         connection.Close(); 
         } 
        } 
    } 
    

    GetBulkCopyFailedData() then opens a new connection to the database, creates a transaction, and begins bulk copying the data one row at a time. It does so by reading through the supplied DataReader and copying each row into an empty DataTable. The DataTable is then bulk copied into the destination database, and any exceptions resulting from this are caught, documented (along with the DataRow that caused it), and the cycle then repeats itself with the next row. At the end of the DataReader we rollback the transaction and return the complete error message. Fixing the problems in the data source should now be a breeze.

    を使用

    /// <summary> 
    /// Build an error message with the failed records and their related exceptions. 
    /// </summary> 
    /// <param name="connectionString">Connection string to the destination database</param> 
    /// <param name="tableName">Table name into which the data will be bulk copied.</param> 
    /// <param name="dataReader">DataReader to bulk copy</param> 
    /// <returns>Error message with failed constraints and invalid data rows.</returns> 
    public static string GetBulkCopyFailedData(
        string connectionString, 
        string tableName, 
        IDataReader dataReader) 
    { 
        StringBuilder errorMessage = new StringBuilder("Bulk copy failures:" + Environment.NewLine); 
        SqlConnection connection = null; 
        SqlTransaction transaction = null; 
        SqlBulkCopy bulkCopy = null; 
        DataTable tmpDataTable = new DataTable(); 
    
        try 
        { 
         connection = new SqlConnection(connectionString); 
         connection.Open(); 
         transaction = connection.BeginTransaction(); 
         bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.CheckConstraints, transaction); 
         bulkCopy.DestinationTableName = tableName; 
    
         // create a datatable with the layout of the data. 
         DataTable dataSchema = dataReader.GetSchemaTable(); 
         foreach (DataRow row in dataSchema.Rows) 
         { 
         tmpDataTable.Columns.Add(new DataColumn(
          row["ColumnName"].ToString(), 
          (Type)row["DataType"])); 
         } 
    
         // create an object array to hold the data being transferred into tmpDataTable 
         //in the loop below. 
         object[] values = new object[dataReader.FieldCount]; 
    
         // loop through the source data 
         while (dataReader.Read()) 
         { 
         // clear the temp DataTable from which the single-record bulk copy will be done 
         tmpDataTable.Rows.Clear(); 
    
         // get the data for the current source row 
         dataReader.GetValues(values); 
    
         // load the values into the temp DataTable 
         tmpDataTable.LoadDataRow(values, true); 
    
         // perform the bulk copy of the one row 
         try 
         { 
          bulkCopy.WriteToServer(tmpDataTable); 
         } 
         catch (Exception ex) 
         { 
          // an exception was raised with the bulk copy of the current row. 
          // The row that caused the current exception is the only one in the temp 
          // DataTable, so document it and add it to the error message. 
          DataRow faultyDataRow = tmpDataTable.Rows[0]; 
          errorMessage.AppendFormat("Error: {0}{1}", ex.Message, Environment.NewLine); 
          errorMessage.AppendFormat("Row data: {0}", Environment.NewLine); 
          foreach (DataColumn column in tmpDataTable.Columns) 
          { 
           errorMessage.AppendFormat(
            "\tColumn {0} - [{1}]{2}", 
            column.ColumnName, 
            faultyDataRow[column.ColumnName].ToString(), 
            Environment.NewLine); 
          } 
         } 
         } 
        } 
        catch (Exception ex) 
        { 
         throw new Exception(
         "Unable to document SqlBulkCopy errors. See inner exceptions for details.", 
         ex); 
        } 
        finally 
        { 
         if (transaction != null) 
         { 
         transaction.Rollback(); 
         } 
         if (connection.State != ConnectionState.Closed) 
         { 
         connection.Close(); 
         } 
        } 
        return errorMessage.ToString(); 
    
  • 関連する問題