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
2020-06-09 21:10:20 +02:00

137 lines
4.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
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)
.ToArray();
//ExecuteBulkInsertInBatches(entityType.Name, properties, entries);
ExecuteBulkInsert(entityType.Name, properties, entries);
}
private static void ExecuteBulkInsertInBatches(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();
}
}
private static void ExecuteBulkInsert(string tableName,
IReadOnlyCollection<string> columns,
IEnumerable entries)
{
using var session = NHibernateHelper.OpenSession();
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)
{
foreach (var column in columns)
{
var value = GetPropertyValue(entry, column);
query.SetParameter(parameterIndex, value);
parameterIndex++;
}
}
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();
}
}
}