test
This commit is contained in:
parent
0f335617b4
commit
e9c638b155
@ -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 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;
|
var value = GetPropertyValue(entry, column);
|
||||||
cmd.CommandText = queryStringComplete;
|
query.SetParameter(parameterIndex, value);
|
||||||
cmd.ExecuteNonQuery();
|
parameterIndex++;
|
||||||
cmd.Parameters.Clear();
|
|
||||||
sb.Clear();
|
|
||||||
batchSize = 0;
|
|
||||||
p = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle the last few stragglers
|
query.ExecuteUpdate();
|
||||||
if (batchSize > 0)
|
}
|
||||||
|
|
||||||
|
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();;)
|
||||||
{
|
{
|
||||||
var queryStringComplete = queryString + sb;
|
sb.Append("(");
|
||||||
cmd.CommandText = queryStringComplete;
|
for (var col = 0; col < columns.Count; col++)
|
||||||
cmd.ExecuteNonQuery();
|
{
|
||||||
|
sb.Append($"?");
|
||||||
|
if (col < columns.Count - 1) sb.Append(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e.MoveNext())
|
||||||
|
{
|
||||||
|
sb.Append(");");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sb.AppendLine("),");
|
||||||
}
|
}
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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]
|
||||||
|
Reference in New Issue
Block a user