Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tablename param #39

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 59 additions & 34 deletions src/Dapper.Bulk/DapperBulk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ public static class DapperBulk
/// <typeparam name="T">The type being inserted.</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="data">Entities to insert</param>
/// <param name="tableName">TableName</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="batchSize">Number of bulk items inserted together, 0 (the default) if all</param>
/// <param name="bulkCopyTimeout">Number of seconds before bulk command execution timeout, 30 (the default)</param>
/// <param name="identityInsert">Usage of db generated ids. By default DB generated IDs are used (identityInsert=false)</param>
public static void BulkInsert<T>(this SqlConnection connection, IEnumerable<T> data, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
public static void BulkInsert<T>(this SqlConnection connection, IEnumerable<T> data, string tableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
var type = typeof(T);
BulkInsert(connection,type,data.Cast<object>(),transaction,batchSize,bulkCopyTimeout,identityInsert);
BulkInsert(connection, type, data.Cast<object>(), tableName, transaction, batchSize, bulkCopyTimeout, identityInsert);
}

/// <summary>
Expand All @@ -39,28 +40,34 @@ public static void BulkInsert<T>(this SqlConnection connection, IEnumerable<T> d
/// <param name="connection">Open SqlConnection</param>
/// <param name="type">The type being inserted.</param>
/// <param name="data">Entities to insert</param>
/// <param name="tableName">TableName</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="batchSize">Number of bulk items inserted together, 0 (the default) if all</param>
/// <param name="bulkCopyTimeout">Number of seconds before bulk command execution timeout, 30 (the default)</param>
/// <param name="identityInsert">Usage of db generated ids. By default DB generated IDs are used (identityInsert=false)</param>
public static void BulkInsert(this SqlConnection connection, Type type, IEnumerable<object> data, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
var tableName = TableMapper.GetTableName(type);
public static void BulkInsert(this SqlConnection connection, Type type, IEnumerable<object> data, string tableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
tableName = string.IsNullOrWhiteSpace(tableName) ? TableMapper.GetTableName(type) : tableName;
var allProperties = PropertiesCache.TypePropertiesCache(type);
var keyProperties = PropertiesCache.KeyPropertiesCache(type);
var computedProperties = PropertiesCache.ComputedPropertiesCache(type);
var columns = PropertiesCache.GetColumnNamesCache(type);

var insertProperties = allProperties.Except(computedProperties).ToList();

if (!identityInsert)
insertProperties = insertProperties.Except(keyProperties).ToList();

var (identityInsertOn, identityInsertOff, sqlBulkCopyOptions) = GetIdentityInsertOptions(identityInsert, tableName);

var insertPropertiesString = GetColumnsStringSqlServer(insertProperties, columns);
var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);

if (connection.State != ConnectionState.Open)
{
connection.Open();
}

connection.Execute($@"SELECT TOP 0 {insertPropertiesString} INTO {tempToBeInserted} FROM {FormatTableName(tableName)} target WITH(NOLOCK);", null, transaction);

using (var bulkCopy = new SqlBulkCopy(connection, sqlBulkCopyOptions, transaction))
Expand All @@ -85,15 +92,16 @@ public static void BulkInsert(this SqlConnection connection, Type type, IEnumera
/// <typeparam name="T">The element type of the array</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="data">Entities to insert</param>
/// <param name="tableName">TableName</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="batchSize">Number of bulk items inserted together, 0 (the default) if all</param>
/// <param name="bulkCopyTimeout">Number of seconds before bulk command execution timeout, 30 (the default)</param>
/// <param name="identityInsert">Usage of db generated ids. By default DB generated IDs are used (identityInsert=false)</param>
/// <returns>Inserted entities</returns>
public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connection, IEnumerable<T> data, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connection, IEnumerable<T> data, string tableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
var type = typeof(T);
var tableName = TableMapper.GetTableName(type);
tableName = string.IsNullOrWhiteSpace(tableName) ? TableMapper.GetTableName(type) : tableName;
var allProperties = PropertiesCache.TypePropertiesCache(type);
var keyProperties = PropertiesCache.KeyPropertiesCache(type);
var computedProperties = PropertiesCache.ComputedPropertiesCache(type);
Expand All @@ -102,25 +110,30 @@ public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connectio
if (keyProperties.Count == 0)
{
var dataList = data.ToList();
connection.BulkInsert(dataList, transaction, batchSize, bulkCopyTimeout);
connection.BulkInsert(dataList, tableName, transaction, batchSize, bulkCopyTimeout);
return dataList;
}

var insertProperties = allProperties.Except(computedProperties).ToList();

if (!identityInsert)
insertProperties = insertProperties.Except(keyProperties).ToList();

var (identityInsertOn, identityInsertOff, sqlBulkCopyOptions) = GetIdentityInsertOptions(identityInsert, tableName);
var keyPropertiesString = GetColumnsStringSqlServer(keyProperties,columns);

var keyPropertiesString = GetColumnsStringSqlServer(keyProperties, columns);
var keyPropertiesInsertedString = GetColumnsStringSqlServer(keyProperties, columns, "inserted.");
var insertPropertiesString = GetColumnsStringSqlServer(insertProperties, columns);
var allPropertiesString = GetColumnsStringSqlServer(allProperties, columns, "target.");

var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);
var tempInsertedWithIdentity = $"@TempInserted_{tableName}".Replace(".", string.Empty);

if (connection.State != ConnectionState.Open)
{
connection.Open();
}

connection.Execute($"SELECT TOP 0 {insertPropertiesString} INTO {tempToBeInserted} FROM {FormatTableName(tableName)} target WITH(NOLOCK);", null, transaction);

using (var bulkCopy = new SqlBulkCopy(connection, sqlBulkCopyOptions, transaction))
Expand All @@ -133,7 +146,7 @@ public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connectio

var table = string.Join(", ", keyProperties.Select(k => $"[{(columns.ContainsKey(k.Name) ? columns[k.Name] : k.Name)}] bigint"));
var joinOn = string.Join(" AND ", keyProperties.Select(k => $"target.[{(columns.ContainsKey(k.Name) ? columns[k.Name] : k.Name)}] = ins.[{(columns.ContainsKey(k.Name) ? columns[k.Name] : k.Name)}]"));

return connection.Query<T>($@"
{identityInsertOn}
DECLARE {tempInsertedWithIdentity} TABLE ({table})
Expand All @@ -154,29 +167,35 @@ public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connectio
/// <typeparam name="T">The type being inserted.</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="data">Entities to insert</param>
/// <param name="tableName">TableName</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="batchSize">Number of bulk items inserted together, 0 (the default) if all</param>
/// <param name="bulkCopyTimeout">Number of seconds before bulk command execution timeout, 30 (the default)</param>
/// <param name="identityInsert">Usage of db generated ids. By default DB generated IDs are used (identityInsert=false)</param>
public static async Task BulkInsertAsync<T>(this SqlConnection connection, IEnumerable<T> data, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
public static async Task BulkInsertAsync<T>(this SqlConnection connection, IEnumerable<T> data, string tableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
var type = typeof(T);
var tableName = TableMapper.GetTableName(type);
tableName = string.IsNullOrWhiteSpace(tableName) ? TableMapper.GetTableName(type) : tableName;
var allProperties = PropertiesCache.TypePropertiesCache(type);
var keyProperties = PropertiesCache.KeyPropertiesCache(type);
var computedProperties = PropertiesCache.ComputedPropertiesCache(type);
var columns = PropertiesCache.GetColumnNamesCache(type);

var insertProperties = allProperties.Except(computedProperties).ToList();

if (!identityInsert)
insertProperties = insertProperties.Except(keyProperties).ToList();

var (identityInsertOn, identityInsertOff, sqlBulkCopyOptions) = GetIdentityInsertOptions(identityInsert, tableName);
var insertPropertiesString = GetColumnsStringSqlServer(insertProperties,columns);

var insertPropertiesString = GetColumnsStringSqlServer(insertProperties, columns);
var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);

if (connection.State != ConnectionState.Open)
{
connection.Open();
}

await connection.ExecuteAsync($@"SELECT TOP 0 {insertPropertiesString} INTO {tempToBeInserted} FROM {FormatTableName(tableName)} target WITH(NOLOCK);", null, transaction);

using (var bulkCopy = new SqlBulkCopy(connection, sqlBulkCopyOptions, transaction))
Expand All @@ -202,15 +221,16 @@ await connection.ExecuteAsync($@"
/// <typeparam name="T">The type being inserted.</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="data">Entities to insert</param>
/// <param name="tableName">TableName</param>
/// <param name="transaction">The transaction to run under, null (the default) if none</param>
/// <param name="batchSize">Number of bulk items inserted together, 0 (the default) if all</param>
/// <param name="bulkCopyTimeout">Number of seconds before bulk command execution timeout, 30 (the default)</param>
/// <param name="identityInsert">Usage of db generated ids. By default DB generated IDs are used (identityInsert=false)</param>
/// <returns>Inserted entities</returns>
public static async Task<IEnumerable<T>> BulkInsertAndSelectAsync<T>(this SqlConnection connection, IEnumerable<T> data, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
public static async Task<IEnumerable<T>> BulkInsertAndSelectAsync<T>(this SqlConnection connection, IEnumerable<T> data, string tableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30, bool identityInsert = false)
{
var type = typeof(T);
var tableName = TableMapper.GetTableName(type);
tableName = string.IsNullOrWhiteSpace(tableName) ? TableMapper.GetTableName(type) : tableName;
var allProperties = PropertiesCache.TypePropertiesCache(type);
var keyProperties = PropertiesCache.KeyPropertiesCache(type);
var computedProperties = PropertiesCache.ComputedPropertiesCache(type);
Expand All @@ -219,28 +239,33 @@ public static async Task<IEnumerable<T>> BulkInsertAndSelectAsync<T>(this SqlCon
if (keyProperties.Count == 0)
{
var dataList = data.ToList();
await connection.BulkInsertAsync(dataList, transaction, batchSize, bulkCopyTimeout);
await connection.BulkInsertAsync(dataList, tableName, transaction, batchSize, bulkCopyTimeout);
return dataList;
}

var insertProperties = allProperties.Except(computedProperties).ToList();

if (!identityInsert)
insertProperties = insertProperties.Except(keyProperties).ToList();

var (identityInsertOn, identityInsertOff, sqlBulkCopyOptions) = GetIdentityInsertOptions(identityInsert, tableName);
var keyPropertiesString = GetColumnsStringSqlServer(keyProperties,columns);
var keyPropertiesInsertedString = GetColumnsStringSqlServer(keyProperties,columns, "inserted.");
var insertPropertiesString = GetColumnsStringSqlServer(insertProperties,columns);

var keyPropertiesString = GetColumnsStringSqlServer(keyProperties, columns);
var keyPropertiesInsertedString = GetColumnsStringSqlServer(keyProperties, columns, "inserted.");
var insertPropertiesString = GetColumnsStringSqlServer(insertProperties, columns);
var allPropertiesString = GetColumnsStringSqlServer(allProperties, columns, "target.");

var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);
var tempInsertedWithIdentity = $"@TempInserted_{tableName}".Replace(".", string.Empty);

if (connection.State != ConnectionState.Open)
{
connection.Open();
}

await connection.ExecuteAsync($@"SELECT TOP 0 {insertPropertiesString} INTO {tempToBeInserted} FROM {FormatTableName(tableName)} target WITH(NOLOCK);", null, transaction);

using (var bulkCopy = new SqlBulkCopy(connection,sqlBulkCopyOptions, transaction))
using (var bulkCopy = new SqlBulkCopy(connection, sqlBulkCopyOptions, transaction))
{
bulkCopy.BulkCopyTimeout = bulkCopyTimeout;
bulkCopy.BatchSize = batchSize;
Expand Down Expand Up @@ -272,7 +297,7 @@ private static string GetColumnsStringSqlServer(IEnumerable<PropertyInfo> proper

return string.Join(", ", properties.Select(property => $"{tablePrefix}[{columnNames[property.Name]}] "));
}

private static DataTable ToDataTable<T>(IEnumerable<T> data, IList<PropertyInfo> properties)
{
var typeCasts = new Type[properties.Count];
Expand Down Expand Up @@ -339,9 +364,9 @@ internal static string FormatTableName(string table)
}

private static (string identityInsertOn, string identityInsertOff, SqlBulkCopyOptions bulkCopyOptions)
GetIdentityInsertOptions(bool identityInsert, string tableName)
=> identityInsert
? ($"SET IDENTITY_INSERT {FormatTableName(tableName)} ON",
$"SET IDENTITY_INSERT {FormatTableName(tableName)} OFF", SqlBulkCopyOptions.KeepIdentity)
: (string.Empty, string.Empty, SqlBulkCopyOptions.Default);
GetIdentityInsertOptions(bool identityInsert, string tableName)=> (string.Empty, string.Empty, SqlBulkCopyOptions.Default);
//=> identityInsert
// ? ($"SET IDENTITY_INSERT {FormatTableName(tableName)} ON",
// $"SET IDENTITY_INSERT {FormatTableName(tableName)} OFF", SqlBulkCopyOptions.KeepIdentity)
// : (string.Empty, string.Empty, SqlBulkCopyOptions.Default);
}