2009-07-27 38 views
17

Tôi đang sử dụng SQLBulkCopy để di chuyển lượng lớn dữ liệu. Tôi đã triển khai sự kiện thông báo để thông báo cho tôi mỗi lần một số hàng nhất định đã được xử lý, nhưng sự kiện OnSqlRowsCopied không kích hoạt khi công việc được hoàn thành. Làm thế nào để tôi nhận được tổng số hàng được sao chép khi máy chủ SQLBulkCopy writetoserver hoàn tất?Số lượng hàng SQLBulkCopy đếm khi hoàn thành

Trả lời

3

Tôi nghĩ bạn phải chạy truy vấn COUNT() trên bảng sau khi kết thúc, như trong ví dụ MSDN here.

Ngoài ra, bạn không thể nói trước? ví dụ. nếu bạn đang chuyển một DataTable sang WriteToServer() thì bạn biết có bao nhiêu bản ghi bằng cách thực hiện một .Rows.Count trên nó.

+0

và nếu bạn đang sử dụng một IDataReader bạn chỉ có thể bọc nó, có nên không bao giờ thực sự có nhu cầu gọi số nhưng một hack của nó có thể làm việc –

+0

@Sam, làm thế nào để bạn có nghĩa là "quấn nó "? Tôi có một 'SqlDataReader', và điều gần nhất với một hàng đếm là thuộc tính' RecordsAffected' luôn là -1 trong trường hợp này ... – chezy525

+0

Đây là phương thức an toàn hơn so với những cái được liệt kê dưới đây , truy cập vào một lĩnh vực riêng có thể phá vỡ trong tương lai mà không cần cảnh báo (Microsoft có thể thay đổi việc triển khai API công khai mà không vi phạm API công khai bằng cách thay đổi tên trường), nhưng truy vấn đếm vẫn hoạt động. –

24

Sau đây Hack (sử dụng phản ánh) là một lựa chọn:

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

Và sau đó sử dụng các lớp như sau:

int rowsCopied = SqlBulkCopyHelper.GetRowsCopied(bulkCopyObjectInYourCode); 

Hope this helps.

+7

Tại sao không làm cho nó trở thành một phương pháp mở rộng? public static int GetRowsCopied (SqlBulkCopy bulkCopy) – mhenry1384

+0

Mối quan tâm duy nhất của tôi ở đây là nó nhận được một trường nội bộ và không chơi với API công cộng. Trường nội bộ đó có thể thay đổi trong quá trình triển khai trong tương lai mà không vi phạm API và điều đó sẽ phá vỡ mã này. (Nó có thể không chắc, nhưng có thể, và tôi đã từng thấy những thứ như thế xảy ra trước đây.) Thật nguy hiểm khi truy cập vào các lĩnh vực tư nhân vì chính xác lý do này - nó có thể hoạt động hôm nay, nhưng không có gì đảm bảo nó sẽ hoạt động Ngày mai. (Thực sự, sẽ rất tuyệt nếu Microsoft vừa mới phát hành một tài sản công cộng ở đây.) –

4

Để hoàn thành, tôi đã triển khai như một phương thức mở rộng và bao gồm không gian tên. Sao chép và dán lớp này nếu bạn muốn có giải pháp nhanh để nhận số lượng đã sao chép. Lưu ý: Số lượng này không tính đến số hàng thực sự được chèn vào khi Bỏ qua trùng lặp được đặt thành BẬT.

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

Bằng cách sử dụng SqlBulkCopy.SqlRowsCopied Event (Xảy ra mỗi khi số lượng hàng theo quy định của NotifyAfter bất động sản đã được xử lý), chúng tôi có thể đạt được SqlBulkCopy Row Đếm Khi Hoàn thành.

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

Đây là những gì tôi đã làm - đó là một sửa đổi nhỏ dung dịch Rahul Modi trong chủ đề này (về cơ bản nó chỉ đặt sự kiện inline SqlRowsCopied, mà tôi nghĩ là một chút bụi trong trường hợp này vì tạo ra các xử lý sự kiện mới phương pháp):

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; 
    } 
} 
Các vấn đề liên quan