sqlbulkcopyoptions keepidentity example sql-server sqlbulkcopy

sql-server - keepidentity - sqlbulkcopy example



Recuento de filas de SQLBulkCopy cuando se complete (5)

Estoy usando SQLBulkCopy para mover grandes cantidades de datos. Implementé el evento de notificación para notificarme cada vez que se haya procesado un cierto número de filas, pero el evento OnSqlRowsCopied no se activa cuando se completa el trabajo. ¿Cómo obtengo el número total de filas copiadas cuando finaliza el writetoserver de SQLBulkCopy?


Al usar el SqlBulkCopy.SqlRowsCopied Event (se produce cada vez que se ha procesado el número de filas especificadas por la propiedad NotifyAfter ) podemos lograr el conteo de filas de SQLBulkCopy cuando se 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; }


Creo que tienes que ejecutar una consulta COUNT () en la tabla después de terminar, como en el ejemplo de MSDN here .

Aparte de eso, ¿no puedes decirlo por adelantado? por ejemplo, si está pasando un DataTable a WriteToServer (), entonces sabrá cuántos registros haciendo un .Rows.Count en él.


El siguiente hack (usando la reflexión) es una opció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); } }

Y luego use la clase de la siguiente manera:

int rowsCopied = SqlBulkCopyHelper.GetRowsCopied(bulkCopyObjectInYourCode);

Espero que esto ayude.


Esto es lo que hice: es una pequeña modificación de la solución de Rahul Modi en este hilo (básicamente, solo pone el evento SqlRowsCopied en línea, lo que creo que es un poco más limpio en este caso que crear el nuevo método del controlador de eventos):

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


Para completar, he implementado como un método de extensión e incluí el espacio de nombres. Copie y pegue esta clase si desea una solución rápida para obtener el recuento copiado. Nota: este recuento no tiene en cuenta el número de filas realmente insertadas cuando Ignorar duplicados está configurado en ACTIVADO.

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