using System; using System.Collections; using System.Collections.Generic; using System.Data.Common; 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); BuildBulkInsertQuery(entityType.Name, properties, entries); } private static void GetParametersValues(string tableName, IEnumerable propertyNames, IEnumerable entries) { static object GetPropertyValue(object o, string propertyName) { //Debug.Assert(propertyName != null, nameof(propertyName) + " != null"); var type = o.GetType(); var property = type.GetProperty(propertyName); //Debug.Assert(property != null, nameof(property) + " != null"); var propertyValue = property?.GetValue(o); return propertyValue; } var fields = propertyNames as string[] ?? propertyNames.ToArray(); var i = 0; foreach (var entry in entries) { ++i; Console.WriteLine($"Entry number {i}"); foreach (var propertyName in fields) { var propertyValue = GetPropertyValue(entry, propertyName); Console.WriteLine($"Property name={propertyName}, value={propertyValue}"); } Console.WriteLine(); } } private static void BuildBulkInsertQuery(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(); } } public static void BulkInsert1(IEnumerable persons) { using var session = NHibernateHelper.OpenSession(); var cmd = session.Connection.CreateCommand(); var queryString = "INSERT INTO Person (Id, FirstName, LastName) VALUES\n"; var sb = new StringBuilder(); var batchSize = 0; var p = 1; //the current paramter name (i.e. "@p1") we're going to use DbParameter CreateDbParameter(object value) { var pm = cmd.CreateParameter(); pm.Value = value; return pm; } foreach (var person in persons) { //Build the names of the parameters var pId = $"@p{p}"; //the "Id" parameter name (i.e. "p1") var pFirstName = $"@p{p + 1}"; var pLastName = $"@p{p + 2}"; p += 3; //Build a single "(p1, p2)" row var row = $"({pId}, {pFirstName}, {pLastName})"; //a single values tuple //Add the row to our running SQL batch if (batchSize > 0) sb.AppendLine(","); sb.Append(row); batchSize += 1; // Add the parameter values for this row cmd.Parameters.AddRange(new[] { CreateDbParameter(person.Id), CreateDbParameter(person.FirstName), CreateDbParameter(person.LastName) }); if (batchSize >= 5) { 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(); } } } }