using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using NPoco; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence { public class SqlServerBulkSqlInsertProvider : IBulkSqlInsertProvider { public int BulkInsertRecords(IUmbracoDatabase database, IEnumerable records) { var recordsA = records.ToArray(); if (recordsA.Length == 0) return 0; var pocoData = database.PocoDataFactory.ForType(typeof(T)); if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T)); return database.DatabaseType.IsSqlServer2008OrLater() ? BulkInsertRecordsSqlServer(database, pocoData, recordsA) : BulkInsertRecordsWithCommands(database, recordsA); } /// /// Bulk-insert records using commands. /// /// The type of the records. /// The database. /// The records. /// The number of records that were inserted. private static int BulkInsertRecordsWithCommands(IUmbracoDatabase database, T[] records) { foreach (var command in database.GenerateBulkInsertCommands(records)) command.ExecuteNonQuery(); return records.Length; // what else? } /// /// Bulk-insert records using SqlServer BulkCopy method. /// /// The type of the records. /// The database. /// The PocoData object corresponding to the record's type. /// The records. /// The number of records that were inserted. private int BulkInsertRecordsSqlServer(IUmbracoDatabase database, PocoData pocoData, IEnumerable records) { // create command against the original database.Connection using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty)) { // use typed connection and transaction or SqlBulkCopy var tConnection = NPocoDatabaseExtensions.GetTypedConnection(database.Connection); var tTransaction = NPocoDatabaseExtensions.GetTypedTransaction(command.Transaction); var tableName = pocoData.TableInfo.TableName; var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider; if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider."); using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName }) using (var bulkReader = new PocoDataDataReader(records, pocoData, syntax)) { //we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared //to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses //the names instead of their ordering. foreach (var col in bulkReader.ColumnMappings) { copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn); } copy.WriteToServer(bulkReader); return bulkReader.RecordsAffected; } } } } }