using System.Collections; using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Text; using ConsoleApp1.Model; namespace ConsoleApp1.ORM { public class BulkQuery { public static void BulkInsert(IEnumerable entries) { var entityType = typeof(TEntity); var properties = entityType.GetProperties() .Select(p => p.Name) .ToArray(); //ExecuteBulkInsertInBatches(entityType.Name, properties, entries); ExecuteBulkInsert(entityType.Name, properties, entries); } private static void ExecuteBulkInsertInBatches(string tableName, IEnumerable propertyNames, IEnumerable entries, int maxBatchSize = 5) { using var session = NHibernateHelper.OpenSession(); var cmd = session.Connection.CreateCommand(); var columns = propertyNames as string[] ?? propertyNames.ToArray(); var queryString = $"INSERT INTO {tableName} ({string.Join(',', columns)}) VALUES\n"; var sb = new StringBuilder(); DbParameter CreateDbParameter(object value) { var pm = cmd.CreateParameter(); pm.Value = value; return pm; } static object GetPropertyValue(object o, string propertyName) => o.GetType().GetProperty(propertyName)?.GetValue(o); var batchSize = 0; var p = 0; foreach (var entry in entries) { // Build the names of the parameters var row = new StringBuilder("("); for (var ii = 0; ii < columns.Length; ii++) { row.Append($"@p{p + ii}"); if (ii < columns.Length - 1) row.Append(","); // Set parameter value var value = GetPropertyValue(entry, columns[ii]); cmd.Parameters.Add(CreateDbParameter(value)); } p += columns.Length; row.Append(")"); // Add the row to our running SQL batch if (batchSize > 0) sb.AppendLine(","); sb.Append(row); batchSize += 1; if (batchSize >= maxBatchSize) { var queryStringComplete = queryString + sb + ";"; cmd.CommandText = queryStringComplete; cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); sb.Clear(); batchSize = 0; p = 1; } } // handle the last few stragglers if (batchSize > 0) { var queryStringComplete = queryString + sb + ";"; cmd.CommandText = queryStringComplete; cmd.ExecuteNonQuery(); } } private static void ExecuteBulkInsert(string tableName, IReadOnlyCollection columns, IEnumerable entries) { using var session = NHibernateHelper.OpenSession(); var queryString = BuildBulkInsertQueryString(tableName, columns, entries); var query = session.CreateSQLQuery(queryString); static object GetPropertyValue(object o, string propertyName) => o.GetType().GetProperty(propertyName)?.GetValue(o); var parameterIndex = 0; foreach (var entry in entries) { foreach (var column in columns) { var value = GetPropertyValue(entry, column); query.SetParameter(parameterIndex, value); parameterIndex++; } } query.ExecuteUpdate(); } private static string BuildBulkInsertQueryString(string tableName, IReadOnlyCollection columns, IEnumerable entries) { var queryString = $"INSERT INTO {tableName} ({string.Join(',', columns)}) VALUES"; var sb = new StringBuilder(queryString).AppendLine(); var e = entries.GetEnumerator(); for (e.MoveNext();;) { sb.Append("("); for (var col = 0; col < columns.Count; col++) { sb.Append($"?"); if (col < columns.Count - 1) sb.Append(","); } if (!e.MoveNext()) { sb.Append(");"); break; } sb.AppendLine("),"); } return sb.ToString(); } } }