This repository has been archived on 2020-06-09. You can view files and clone it, but cannot push or open issues or pull requests.
dotnet-nhibernate-test/ConsoleApp1/ORM/BulkQuery.cs

173 lines
6.3 KiB
C#
Raw Normal View History

2020-06-08 22:12:01 +00:00
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<TEntity>(IEnumerable<TEntity> 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<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,
IEnumerable<string> 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<Person> 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();
}
}
}
}