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.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<TEntity>(IEnumerable<TEntity> 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<string> 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<string> propertyNames,
IEnumerable entries,
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();
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";
var sb = new StringBuilder();
static object GetPropertyValue(object o, string propertyName) => o.GetType().GetProperty(propertyName)?.GetValue(o);
var batchSize = 0;
var p = 1; //the current paramter name (i.e. "@p1") we're going to use
DbParameter CreateDbParameter(object value)
var parameterIndex = 0;
foreach (var entry in entries)
{
var pm = cmd.CreateParameter();
pm.Value = value;
return pm;
}
foreach (var person in persons)
foreach (var column in columns)
{
//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;
var value = GetPropertyValue(entry, column);
query.SetParameter(parameterIndex, value);
parameterIndex++;
}
}
//handle the last few stragglers
if (batchSize > 0)
{
var queryStringComplete = queryString + sb;
cmd.CommandText = queryStringComplete;
cmd.ExecuteNonQuery();
query.ExecuteUpdate();
}
private static string BuildBulkInsertQueryString(string tableName,
IReadOnlyCollection<string> 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();
}
}
}

View File

@ -72,14 +72,16 @@ namespace ConsoleApp1.Repository
[Test]
public void TestBulkInsert()
{
static IEnumerable<Person> 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]