完成时SQLBulkCopy行计数

Sch*_*tzE 23 sql-server sqlbulkcopy

我正在使用SQLBulkCopy来移动大量数据.我实现了通知事件,以便每次处理完一定数量的行时通知我,但是当作业完成时,OnSqlRowsCopied事件不会触发.如何在SQLBulkCopy writetoserver完成时获取复制的总行数?

Ben*_*nzi 31

以下hack(使用反射)是一个选项:

    /// <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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后使用如下类:

int rowsCopied = SqlBulkCopyHelper.GetRowsCopied(bulkCopyObjectInYourCode);
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 为什么不把它作为扩展方法呢?public static int GetRowsCopied(this SqlBulkCopy bulkCopy) (10认同)
  • 我唯一担心的是它获得了一个内部字段,并且不使用公共API.在不破坏API的情况下,该内部字段可能会在未来的实现中发生变化,这会破坏此代码.(这可能不太可能,但有可能,而且我已经看到过类似的事情发生过.).出于这个原因访问私有字段有点危险 - 它今天可能有用,但不能保证它会起作用明天.(真的,如果微软刚刚在这里公开了一个公共财产,那就好了.) (2认同)

小智 7

为了完整性,我已经实现了扩展方法并包含了命名空间.如果您想要快速解决方案来获取复制的计数,请复制并粘贴此类.注意:当Ignore Duplicates设置为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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Ari*_*oth 7

这就是我所做的 - 这是对该线程中 Rahul Modi 解决方案的轻微修改(基本上它只是将 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;
   }
}
Run Code Online (Sandbox Code Playgroud)


Rah*_*odi 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;
}
Run Code Online (Sandbox Code Playgroud)


Ron*_*rby 5

设置NotifyAfter为 1。在 的处理程序中SqlRowsCopied,增加一个计数器。后WriteToServer完成,读取计数器。


Ada*_*Dev 0

我认为完成后您必须在表上运行 COUNT() 查询,如此处的 MSDN 示例所示

除此之外,你就不能提前说一下吗?例如,如果您将 DataTable 传递给 WriteToServer(),那么您可以通过对其执行 .Rows.Count 来知道有多少条记录。