173 lines
6.3 KiB
C#
173 lines
6.3 KiB
C#
|
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();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|