This commit is contained in:
Thibaud Gasser 2020-06-09 21:10:20 +02:00
parent 0f335617b4
commit e9c638b155
2 changed files with 53 additions and 87 deletions

View File

@ -1,7 +1,7 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ConsoleApp1.Model; using ConsoleApp1.Model;
@ -13,38 +13,14 @@ namespace ConsoleApp1.ORM
public static void BulkInsert<TEntity>(IEnumerable<TEntity> entries) public static void BulkInsert<TEntity>(IEnumerable<TEntity> entries)
{ {
var entityType = typeof(TEntity); var entityType = typeof(TEntity);
var properties = entityType.GetProperties().Select(p => p.Name); var properties = entityType.GetProperties()
BuildBulkInsertQuery(entityType.Name, properties, entries); .Select(p => p.Name)
.ToArray();
//ExecuteBulkInsertInBatches(entityType.Name, properties, entries);
ExecuteBulkInsert(entityType.Name, properties, entries);
} }
private static void GetParametersValues(string tableName, IEnumerable<string> propertyNames, IEnumerable entries) private static void ExecuteBulkInsertInBatches(string tableName,
{
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<string> propertyNames, IEnumerable<string> propertyNames,
IEnumerable entries, IEnumerable entries,
int maxBatchSize = 5) int maxBatchSize = 5)
@ -108,66 +84,54 @@ namespace ConsoleApp1.ORM
} }
} }
public static void BulkInsert1(IEnumerable<Person> persons) private static void ExecuteBulkInsert(string tableName,
IReadOnlyCollection<string> columns,
IEnumerable entries)
{ {
using var session = NHibernateHelper.OpenSession(); using var session = NHibernateHelper.OpenSession();
var cmd = session.Connection.CreateCommand(); var queryString = BuildBulkInsertQueryString(tableName, columns, entries);
var query = session.CreateSQLQuery(queryString);
var queryString = "INSERT INTO Person (Id, FirstName, LastName) VALUES\n"; static object GetPropertyValue(object o, string propertyName) => o.GetType().GetProperty(propertyName)?.GetValue(o);
var sb = new StringBuilder();
var batchSize = 0; var parameterIndex = 0;
var p = 1; //the current paramter name (i.e. "@p1") we're going to use foreach (var entry in entries)
DbParameter CreateDbParameter(object value)
{ {
var pm = cmd.CreateParameter(); foreach (var column in columns)
pm.Value = value;
return pm;
}
foreach (var person in persons)
{ {
//Build the names of the parameters var value = GetPropertyValue(entry, column);
var pId = $"@p{p}"; //the "Id" parameter name (i.e. "p1") query.SetParameter(parameterIndex, value);
var pFirstName = $"@p{p + 1}"; parameterIndex++;
var pLastName = $"@p{p + 2}"; }
p += 3; }
//Build a single "(p1, p2)" row query.ExecuteUpdate();
var row = $"({pId}, {pFirstName}, {pLastName})"; //a single values tuple }
//Add the row to our running SQL batch private static string BuildBulkInsertQueryString(string tableName,
if (batchSize > 0) sb.AppendLine(","); IReadOnlyCollection<string> columns,
sb.Append(row); IEnumerable entries)
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; var queryString = $"INSERT INTO {tableName} ({string.Join(',', columns)}) VALUES";
cmd.CommandText = queryStringComplete; var sb = new StringBuilder(queryString).AppendLine();
cmd.ExecuteNonQuery(); var e = entries.GetEnumerator();
cmd.Parameters.Clear(); for (e.MoveNext();;)
sb.Clear(); {
batchSize = 0; sb.Append("(");
p = 1; for (var col = 0; col < columns.Count; col++)
} {
sb.Append($"?");
if (col < columns.Count - 1) sb.Append(",");
} }
//handle the last few stragglers if (!e.MoveNext())
if (batchSize > 0)
{ {
var queryStringComplete = queryString + sb; sb.Append(");");
cmd.CommandText = queryStringComplete; break;
cmd.ExecuteNonQuery(); }
} sb.AppendLine("),");
}
return sb.ToString();
} }
} }
} }

View File

@ -72,14 +72,16 @@ namespace ConsoleApp1.Repository
[Test] [Test]
public void TestBulkInsert() public void TestBulkInsert()
{ {
static IEnumerable<Person> GeneratePersons(int num = 3) static Person[] GeneratePersons(int num = 3)
{ {
var ret = new Person[num]; var ret = new Person[num];
for (var ii = 0; ii < num; ii++) ret[ii] = new Person {Id = Guid.NewGuid(), FirstName = "bac", LastName = "fif"}; for (var ii = 0; ii < num; ii++) ret[ii] = new Person {Id = Guid.NewGuid(), FirstName = "bac", LastName = "fif"};
return ret; return ret;
} }
_personRepo.Save(GeneratePersons(10)); var persons = GeneratePersons(10000);
_personRepo.Save(persons);
Assert.AreEqual(10000, _personRepo.RowCount());
} }
[TearDown] [TearDown]