From e9c638b155a8f013f5cf2c8e00c035302af3a2bc Mon Sep 17 00:00:00 2001 From: Thibaud Date: Tue, 9 Jun 2020 21:10:20 +0200 Subject: [PATCH] test --- ConsoleApp1/ORM/BulkQuery.cs | 132 +++++++----------- .../Repository/PersonRepositoryTest.cs | 8 +- 2 files changed, 53 insertions(+), 87 deletions(-) diff --git a/ConsoleApp1/ORM/BulkQuery.cs b/ConsoleApp1/ORM/BulkQuery.cs index 128bf5a..a214fac 100644 --- a/ConsoleApp1/ORM/BulkQuery.cs +++ b/ConsoleApp1/ORM/BulkQuery.cs @@ -1,7 +1,7 @@ -using System; using System.Collections; using System.Collections.Generic; using System.Data.Common; +using System.Diagnostics; using System.Linq; using System.Text; using ConsoleApp1.Model; @@ -13,38 +13,14 @@ namespace ConsoleApp1.ORM public static void BulkInsert(IEnumerable entries) { var entityType = typeof(TEntity); - var properties = entityType.GetProperties().Select(p => p.Name); - BuildBulkInsertQuery(entityType.Name, properties, entries); + var properties = entityType.GetProperties() + .Select(p => p.Name) + .ToArray(); + //ExecuteBulkInsertInBatches(entityType.Name, properties, entries); + ExecuteBulkInsert(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, + private static void ExecuteBulkInsertInBatches(string tableName, IEnumerable propertyNames, IEnumerable entries, int maxBatchSize = 5) @@ -107,67 +83,55 @@ namespace ConsoleApp1.ORM cmd.ExecuteNonQuery(); } } - - public static void BulkInsert1(IEnumerable persons) + + private static void ExecuteBulkInsert(string tableName, + IReadOnlyCollection columns, + IEnumerable entries) { 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 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) { - 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) + foreach (var column in columns) { - var queryStringComplete = queryString + sb; - cmd.CommandText = queryStringComplete; - cmd.ExecuteNonQuery(); - cmd.Parameters.Clear(); - sb.Clear(); - batchSize = 0; - p = 1; + var value = GetPropertyValue(entry, column); + query.SetParameter(parameterIndex, value); + parameterIndex++; } } - - //handle the last few stragglers - if (batchSize > 0) + + 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();;) { - var queryStringComplete = queryString + sb; - cmd.CommandText = queryStringComplete; - cmd.ExecuteNonQuery(); + 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(); } } } \ No newline at end of file diff --git a/ConsoleApp1/Repository/PersonRepositoryTest.cs b/ConsoleApp1/Repository/PersonRepositoryTest.cs index 7a64a00..a9e71ea 100644 --- a/ConsoleApp1/Repository/PersonRepositoryTest.cs +++ b/ConsoleApp1/Repository/PersonRepositoryTest.cs @@ -72,14 +72,16 @@ namespace ConsoleApp1.Repository [Test] public void TestBulkInsert() { - static IEnumerable GeneratePersons(int num = 3) + static Person[] GeneratePersons(int num = 3) { var ret = new Person[num]; for (var ii = 0; ii < num; ii++) ret[ii] = new Person {Id = Guid.NewGuid(), FirstName = "bac", LastName = "fif"}; return ret; } - - _personRepo.Save(GeneratePersons(10)); + + var persons = GeneratePersons(10000); + _personRepo.Save(persons); + Assert.AreEqual(10000, _personRepo.RowCount()); } [TearDown]