Подтвердить что ты не робот

Счетчик строк SQLBulkCopy при завершении

Я использую SQLBulkCopy для перемещения больших объемов данных. Я внедрил событие уведомления, чтобы уведомлять меня каждый раз, когда определенное количество строк было обработано, но событие OnSqlRowsCopied не срабатывает, когда задание завершено. Как получить общее количество строк, скопированных при завершении SQLBulkCopy writetoserver?

4b9b3361

Ответ 1

Я думаю, вам нужно запустить запрос COUNT() в таблице после завершения, как в примере MSDN здесь.

Кроме этого, разве вы не можете сказать впереди? например если вы передаете DataTable на WriteToServer(), тогда вы знаете, сколько записей делает .Rows.Count на нем.

Ответ 2

Следующий взлом (с использованием отражения) является опцией:

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

Надеюсь, что это поможет.

Ответ 3

Для полноты я реализовал как метод расширения и включил пространство имен. Скопируйте и вставьте этот класс, если хотите быстрое решение для получения скопированного счета. Примечание. Этот счетчик не учитывает количество вставленных строк, когда 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);
        }
    }
}

Ответ 4

С помощью SqlBulkCopy.SqlRowsCopied Event (Происходит каждый раз, когда количество строк, указанное свойством NotifyAfter, было обработано), мы можем достичь SQLBulkCopy Row Count When Complete.

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

Ответ 5

Вот что я сделал - это небольшая модификация решения Rahul Modi в этом потоке (в основном это просто вставляет событие SqlRowsCopied inline, которое, по моему мнению, в этом случае немного чище, чем создание нового метода обработчика событий):

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

Ответ 6

Установите NotifyAfter в 1. В обработчике для SqlRowsCopied увеличьте счетчик. После завершения WriteToServer прочитайте счетчик.

Ответ 7

Метод расширения:

(Основываясь на ответе @Benzi)

using System;
using System.Reflection;
using System.Data.SqlClient;
using static System.Reflection.BindingFlags;

namespace Extensions
{
    public static class SqlBulkCopyExtensions
    {
        private static readonly Lazy<FieldInfo> _rowsCopied = new Lazy<FieldInfo>(() => typeof(SqlBulkCopy).GetField("_rowsCopied", NonPublic | GetField | Instance));

        public static int GetRowsCopied(this SqlBulkCopy sqlBulkCopy)
        {
            return (int)_rowsCopied.Value.GetValue(sqlBulkCopy);
        }
    }
}

Проверено & работает с .NET 4.6.1

Обратите внимание, что тип поля - int (в то время как тип свойства в аргументах события - long). Не уверен, что произойдет, если вы скопируете> int.MaxValue строки.