2009-07-27 18 views
17

我正在使用SQLBulkCopy來移動大量數據。我實現了通知事件來通知我每次處理了一定數量的行,但是OnSqlRowsCopied事件在作業完成時不會觸發。如何獲得SQLBulkCopy寫入服務器完成時複製的總行數?SQLBulkCopy行數完成時

回答

3

我想你必須在完成後在表上運行一個COUNT()查詢,如MSDN示例here

除此之外,你不能告訴前面?例如如果你將一個DataTable傳遞給WriteToServer(),那麼你就可以通過對它做一個.Rows.Count來知道有多少條記錄。

+0

,如果你正在使用的IDataReader你可以把它包起來,應該從來沒有真正成爲一個需要調用計數,但它是一個黑客工具,可以工作 – 2009-07-27 22:30:22

+0

@Sam,你的意思是「把它包「?我有一個`SqlDataReader`,最接近行計數的是`RecordsAffected`屬性,在這種情況下總是-1 ... – chezy525 2011-02-03 23:04:44

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); 

希望這有助於。

4

爲了完整性,我已經實現了一個擴展方法幷包含了命名空間。如果您想要快速解決方案以獲取複製的計數,請複製並粘貼此課程。注意:此計數沒有考慮忽略重複設置爲ON時實際插入的行數。

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

通過使用SqlBulkCopy.SqlRowsCopied Event(發生每次由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; 
    } 
}