2009-07-27 8 views
17

SQLBulkCopyを使用して大量のデータを移動しています。特定の行数が処理されるたびに通知イベントを実装しましたが、ジョブの完了時にOnSqlRowsCopiedイベントは発生しません。 SQLBulkCopy writetoserverが完了したときにコピーされる行の総数を取得するにはどうすればよいですか?完了時のSQLBulkCopy行数

答えて

3

MSDNの例hereのように、テーブルの終了後にCOUNT()クエリを実行する必要があると思います。

それ以外は、先を教えていただけませんか?例えばDataTableをWriteToServer()に渡している場合は、.Rows.Countを実行してレコード数を知ることができます。

+0

、あなたがそれをラップすることができたIDataReaderを使用している場合、実際にどのようにあなたがそれを包む」意味ですか、数を呼び出す必要がありますが –

+0

@Samを作業することができ、そのハックがあってはいけません"?私は 'SqlDataReader'を持っています。行数に最も近いものは' RecordsAffected'プロパティです。この場合常に-1です... – chezy525

+0

これは以下のリストよりも安全なメソッドです(フィールド名を変更してパブリックAPIを破棄せずにパブリックAPIの実装を変更する可能性がありますが)カウントクエリは引き続き機能します。 –

24

(リフレクションを使用して)以下のハックはオプションです。その後、

/// <summary> 
    /// Helper class to process the SqlBulkCopy class 
    /// </summary> 
    static class SqlBulkCopyHelper 
    { 
     static FieldInfo rowsCopiedField = null; 

     /// <summary> 
     /// Gets the rows copied from the specified SqlBulkCopy object 
     /// </summary> 
     /// <param name="bulkCopy">The bulk copy.</param> 
     /// <returns></returns> 
     public static int GetRowsCopied(SqlBulkCopy bulkCopy) 
     { 
      if (rowsCopiedField == null) 
      { 
       rowsCopiedField = typeof(SqlBulkCopy).GetField("_rowsCopied", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); 
      } 

      return (int)rowsCopiedField.GetValue(bulkCopy); 
     } 
    } 

、次のようにクラスを使用します。

int rowsCopied = SqlBulkCopyHelper.GetRowsCopied(bulkCopyObjectInYourCode); 

・ホープ、このことができます。

+7

それを拡張メソッドにしてみませんか? public static int GetRowsCopied(this SqlBulkCopy bulkCopy) – mhenry1384

+0

私の唯一の懸念は、内部フィールドを取得し、パブリックAPIで再生しないことです。その内部フィールドは、APIを破棄することなく将来の実装で変更される可能性があり、それはこのコードを破るでしょう。 (それは起こりそうもないかもしれませんが、それは以前に起こったようなものを見てきました)まさにこの理由でプライベートフィールドにアクセスするのは危険です。今日はうまくいくかもしれませんが、それがうまくいくという保証はありません明日。 (Microsoftが公有財産をここに公開したのであれば本当にうれしいだろう) –

4

私は拡張メソッドとして実装しており、名前空間を含んでいます。高速なソリューションでコピーされたカウントを取得する場合は、このクラスをコピーして貼り付けます。注:このカウントでは、[重複を無視]が[オン]に設定されているときに実際に挿入された行の数は考慮されません。 SqlBulkCopy.SqlRowsCopied Eventを使用することにより

namespace System.Data.SqlClient 
{  
    using Reflection; 

    public static class SqlBulkCopyExtension 
    { 
     const String _rowsCopiedFieldName = "_rowsCopied"; 
     static FieldInfo _rowsCopiedField = null; 

     public static int RowsCopiedCount(this SqlBulkCopy bulkCopy) 
     { 
      if (_rowsCopiedField == null) _rowsCopiedField = typeof(SqlBulkCopy).GetField(_rowsCopiedFieldName, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);    
      return (int)_rowsCopiedField.GetValue(bulkCopy); 
     } 
    } 
} 
5

NotifyAfterプロパティで指定した行数が処理されたことをするたびに発生)、我々はときに完全SQLBulkCopy行カウントを達成することができます。ここで

using (SqlBulkCopy s = new SqlBulkCopy(db.Database.Connection as SqlConnection)) 
{ 
    s.SqlRowsCopied += new SqlRowsCopiedEventHandler(sqlBulk_SqlRowsCopied); 
    s.BatchSize = csvFileData.Rows.Count;//DataTable 
    s.NotifyAfter = csvFileData.Rows.Count; 
    foreach (var column in csvFileData.Columns) 
    s.ColumnMappings.Add(column.ToString(), column.ToString()); 
    // Set the timeout. 
    s.BulkCopyTimeout = 60; 
    s.DestinationTableName = "Employee_Data"; 
    s.WriteToServer(csvFileData); 
} 

private static void sqlBulk_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e) 
{ 
    long Count = e.RowsCopied; 
} 
2

は、私がやったことだ - それは、基本的にはそれだけでSqlRowsCopiedイベントをインラインで置く(このスレッドでラーフルモディのソリューションのわずかな変更だ私は新しいイベントハンドラを作成するよりも、このインスタンスのビットクリーンだと思ういます法):

private long InsetData(DataTable dataTable, SqlConnection connection) 
{ 
    using (SqlBulkCopy copier = new SqlBulkCopy(connection)) 
    { 
     var filesInserted = 0L; 

     connection.Open(); 

     copier.DestinationTableName = "dbo.MyTable"; 
     copier.NotifyAfter = dataTable.Rows.Count; 
     copier.SqlRowsCopied += (s, e) => filesInserted = e.RowsCopied; 
     copier.WriteToServer(dataTable); 

     connection.Close(); 

     return filesInserted; 
    } 
} 
関連する問題