using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Diagnostics; namespace Test.SqlCopy { /// /// Copy progress event args /// public class CopyProgressEventArgs : EventArgs { public SqlRowsCopiedEventArgs SqlArgs { get; private set; } public long Total { get; private set; } public Exception Exception { get; private set; } public string TableName { get; private set; } public long Current { get { if (SqlArgs != null) return SqlArgs.RowsCopied; else return Total; } } public CopyProgressEventArgs(SqlRowsCopiedEventArgs args, string tableName, long total) { TableName = tableName; SqlArgs = args; Total = total; } public CopyProgressEventArgs(string tableName, Exception ex) { Exception = ex; TableName = tableName; } /// /// ctor /// /// Nr of rows copied /// Copy is complete public CopyProgressEventArgs(string tableName, long count, long total) : this(new SqlRowsCopiedEventArgs(count), tableName, total) { } } /// /// The actual copy class /// public class CopyData { public event EventHandler CopyProgress; private string _source; private string _destination; private int _timeout; private int _batchSize; private SqlBulkCopyOptions _options; private bool _deleteoption = false; public CopyData(string sourceConnectionString, string destinationConnectionString, SqlBulkCopyOptions options, int timeout, int batchSize) { _source = sourceConnectionString; _destination = destinationConnectionString; _options = options; _batchSize = batchSize; _timeout = timeout; } public CopyData(string sourceConnectionString, string destinationConnectionString, SqlBulkCopyOptions options, int timeout, int batchSize, bool deleteOption) { _source = sourceConnectionString; _destination = destinationConnectionString; _options = options; _batchSize = batchSize; _timeout = timeout; _deleteoption = deleteOption; } public void DeleteTable(string table) { using (SqlConnection destination = new SqlConnection(_destination)) { string sql = string.Format("delete from {0};", table); Trace.TraceInformation("Deleting data from table {0}", table); using (SqlCommand command = new SqlCommand(sql, destination)) { command.CommandTimeout = _timeout; destination.Open(); command.ExecuteNonQuery(); } } } public void CopyTable(string table) { // delete destination rows first if (_deleteoption) DeleteTable(table); using (SqlConnection source = new SqlConnection(_source)) { // get the count of source records, // so we can report on it in the progress overview string sql = string.Format("select count(*) from {0}", table); source.Open(); long rowCount = 0; using (SqlCommand command = new SqlCommand(sql, source)) { command.CommandTimeout = _timeout; rowCount = (int)command.ExecuteScalar(); } Trace.TraceInformation("Starting to copy {0} rows to table {1}", rowCount, table); // get the columns for this table // filter computed columns sql = string.Format(@"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE NOT COLUMNPROPERTY(OBJECT_ID(table_name) ,COLUMN_NAME,'IsComputed') = 1 AND '[' + table_schema + '].[' + table_name + ']' = '{0}'", table); List columns = new List(); using (SqlCommand command = new SqlCommand(sql, source)) { using (SqlDataReader sr = command.ExecuteReader()) { while (sr.Read()) { columns.Add(string.Format("[{0}]", sr["COLUMN_NAME"])); } } } sql = string.Format("select {1} from {0}", table, string.Join(",", columns.ToArray())); using (SqlCommand command = new SqlCommand(sql, source)) { command.CommandTimeout = _timeout; using (IDataReader dr = command.ExecuteReader()) { using (SqlBulkCopy copy = new SqlBulkCopy(_destination, _options)) { copy.BulkCopyTimeout = _timeout; copy.BatchSize = _batchSize; // explicitly map column names foreach (string column in columns) { copy.ColumnMappings.Add(column, column); } // setup notification copy.NotifyAfter = 1000; copy.DestinationTableName = table; // attach event handler copy.SqlRowsCopied += delegate(object sender, SqlRowsCopiedEventArgs e) { if (CopyProgress != null) { CopyProgress.Invoke(sender, new CopyProgressEventArgs(e,table, rowCount)); } }; copy.WriteToServer(dr); // anyone out there? if (CopyProgress != null) { // invoke the progress with the final count CopyProgress.Invoke(copy, new CopyProgressEventArgs(table, rowCount, rowCount)); } } } } } } } }