From 1e731b5ddaf8077553cb7a16824e9a6e6a1be1bb Mon Sep 17 00:00:00 2001 From: Andrey Khvan Date: Sat, 30 Oct 2021 23:25:46 +0600 Subject: [PATCH 1/3] BulkInsertIntoTempTable methods added --- src/Dapper.Bulk/DapperBulk.cs | 145 +++++++++++++++++++++- tests/Dapper.Bulk.Tests/TempTableTests.cs | 100 +++++++++++++++ 2 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 tests/Dapper.Bulk.Tests/TempTableTests.cs diff --git a/src/Dapper.Bulk/DapperBulk.cs b/src/Dapper.Bulk/DapperBulk.cs index 04e0fef..113dcd6 100644 --- a/src/Dapper.Bulk/DapperBulk.cs +++ b/src/Dapper.Bulk/DapperBulk.cs @@ -79,6 +79,101 @@ public static void BulkInsert(this SqlConnection connection, Type type, IEnumera DROP TABLE {tempToBeInserted};", null, transaction); } + + /// + /// Inserts entities into table. + /// by default, the table is named after the data type specified. + /// + /// Open SqlConnection + /// The type being inserted. + /// Entities to insert + /// Entities to insert + /// The transaction to run under, null (the default) if none + /// Number of bulk items inserted together, 0 (the default) if all + /// Number of seconds before bulk command execution timeout, 30 (the default) + /// Usage of db generated ids. By default DB generated IDs are used (identityInsert=false) + public static void BulkInsertIntoTempTable(this SqlConnection connection, Type type, IEnumerable data, string tempTableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30) + { + tempTableName="#"+tempTableName.Replace("#",String.Empty); + + //var tableName = TableMapper.GetTableName(type); + var allProperties = PropertiesCache.TypePropertiesCache(type); + var computedProperties = PropertiesCache.ComputedPropertiesCache(type); + var insertProperties = allProperties.Except(computedProperties).ToList(); + + + var dataTable= ToDataTable(data, insertProperties); + + var sql= CreateTABLE(tempTableName, dataTable); + + connection.Execute(sql, null, transaction); + + using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction)) + { + bulkCopy.BulkCopyTimeout = bulkCopyTimeout; + bulkCopy.BatchSize = batchSize; + bulkCopy.DestinationTableName = tempTableName; + bulkCopy.WriteToServer(dataTable.CreateDataReader()); + } + + } + + + /// + /// Inserts entities into temp table. This table exists only in the current connection. + /// + /// The type being inserted. + /// Open SqlConnection + /// Entities to insert + /// Temp table name + /// The transaction to run under, null (the default) if none + /// Number of bulk items inserted together, 0 (the default) if all + /// Number of seconds before bulk command execution timeout, 30 (the default) + /// Usage of db generated ids. By default DB generated IDs are used (identityInsert=false) + public static void BulkInsertIntoTempTable(this SqlConnection connection, IEnumerable data,string tempTableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30) + { + var type = typeof(T); + BulkInsertIntoTempTable(connection, type, data.Cast(), tempTableName, transaction, batchSize, bulkCopyTimeout); + } + + + /// + /// Inserts entities into temp table. This table exists only in the current connection. + /// by default, the table is named after the data type specified. + /// + /// Open SqlConnection + /// The type being inserted. + /// Entities to insert + /// Entities to insert + /// The transaction to run under, null (the default) if none + /// Number of bulk items inserted together, 0 (the default) if all + /// Number of seconds before bulk command execution timeout, 30 (the default) + /// Usage of db generated ids. By default DB generated IDs are used (identityInsert=false) + public async static Task BulkInsertIntoTempTableAsync(this SqlConnection connection, Type type, IEnumerable data, string tempTableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30) + { + tempTableName = "#" + tempTableName.Replace("#", String.Empty); + + var allProperties = PropertiesCache.TypePropertiesCache(type); + var computedProperties = PropertiesCache.ComputedPropertiesCache(type); + var insertProperties = allProperties.Except(computedProperties).ToList(); + + + var dataTable = ToDataTable(data, insertProperties); + + var sql = CreateTABLE(tempTableName, dataTable); + + await connection.ExecuteAsync(sql, null, transaction); + + using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction)) + { + bulkCopy.BulkCopyTimeout = bulkCopyTimeout; + bulkCopy.BatchSize = batchSize; + bulkCopy.DestinationTableName = tempTableName; + await bulkCopy.WriteToServerAsync(dataTable.CreateDataReader()); + } + + } + /// /// Inserts entities into table s (by default) returns inserted entities. /// @@ -310,7 +405,55 @@ private static DataTable ToDataTable(IEnumerable data, IList return dataTable; } - + + private static string CreateTABLE(string tableName, DataTable table) + { + string sqlsc; + sqlsc = "CREATE TABLE " + tableName + "("; + for (int i = 0; i < table.Columns.Count; i++) + { + sqlsc += "\n [" + table.Columns[i].ColumnName + "] "; + string columnType = table.Columns[i].DataType.ToString(); + switch (columnType) + { + case "System.Int32": + sqlsc += " int "; + break; + case "System.Int64": + sqlsc += " bigint "; + break; + case "System.Int16": + sqlsc += " smallint"; + break; + case "System.Byte": + sqlsc += " tinyint"; + break; + case "System.Decimal": + sqlsc += " decimal "; + break; + case "System.DateTime": + sqlsc += " datetime2(7) "; + break; + case "System.Boolean": + sqlsc += " bit "; + break; + case "System.Guid": + sqlsc += " uniqueidentifier "; + break; + + case "System.String": + default: + sqlsc += string.Format(" nvarchar({0}) ", table.Columns[i].MaxLength == -1 ? "max" : table.Columns[i].MaxLength.ToString()); + break; + } + if (table.Columns[i].AutoIncrement) + sqlsc += " IDENTITY(" + table.Columns[i].AutoIncrementSeed.ToString() + "," + table.Columns[i].AutoIncrementStep.ToString() + ") "; + if (!table.Columns[i].AllowDBNull) + sqlsc += " NOT NULL "; + sqlsc += ","; + } + return sqlsc.Substring(0, sqlsc.Length - 1) + "\n)"; + } internal static string FormatTableName(string table) { if (string.IsNullOrEmpty(table)) diff --git a/tests/Dapper.Bulk.Tests/TempTableTests.cs b/tests/Dapper.Bulk.Tests/TempTableTests.cs new file mode 100644 index 0000000..423b094 --- /dev/null +++ b/tests/Dapper.Bulk.Tests/TempTableTests.cs @@ -0,0 +1,100 @@ +using Dapper.Bulk.Tests.Attributes; +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace Dapper.Bulk.Tests +{ + + public class TempTableTests : SqlServerTestSuite + { + + public enum AnEnum + { + Val1, + Val2 + } + private class TempTableMap + { + [Key] + public int IntField { get; set; } + public int LongField { get; set; } + public byte ByteField { get; set; } + public bool BoolField { get; set; } + public string StringField { get; set; } + public DateTime DateTimeField { get; set; } + public AnEnum EnumField {get;set; } + public Guid GuidField { get; set; } + public Double DoubleField { get; set; } + public float FloatField { get; set; } + public sbyte SByteField { get; set; } + public Char CharleField { get; set; } + public uint UintField { get; set; } + public ulong ULongField { get; set; } + public short ShortField { get; set; } + + } + + [Fact] + public void InsertBulkIntoTempTable() + { + var rnd=new Random(); + + var data = new List(); + for (var i = 0; i < 10000; i++) + { + data.Add(new TempTableMap { + BoolField= rnd.Next(2)==1, + DateTimeField=DateTime.Now, + ByteField=(byte)(rnd.Next(256)-1), + EnumField=Enum.GetValues()[rnd.Next(2)], + GuidField=Guid.NewGuid(), + IntField=rnd.Next(), + LongField=rnd.Next(), + StringField=Guid.NewGuid().ToString(), + CharleField=(Char)(rnd.Next(20,256)), + DoubleField=rnd.NextDouble(), + FloatField=(float)rnd.NextDouble(), + SByteField= (sbyte)(rnd.Next(256) - 128), + ShortField = (short)(rnd.Next(32768) - 128), + UintField = (uint)rnd.Next(1 << 30), + ULongField= (ulong)rnd.Next() + }); + } + + using (var connection = this.GetConnection()) + { + connection.Open(); + connection.BulkInsertIntoTempTable(data,"#temp1"); + var tempTable=connection.Query("select * from #temp1").ToList(); + for(var i=0;i Date: Sat, 30 Oct 2021 23:28:18 +0600 Subject: [PATCH 2/3] some minor changes --- src/Dapper.Bulk/DapperBulk.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Dapper.Bulk/DapperBulk.cs b/src/Dapper.Bulk/DapperBulk.cs index 113dcd6..c5c7a1c 100644 --- a/src/Dapper.Bulk/DapperBulk.cs +++ b/src/Dapper.Bulk/DapperBulk.cs @@ -81,7 +81,7 @@ public static void BulkInsert(this SqlConnection connection, Type type, IEnumera /// - /// Inserts entities into table. + /// Inserts entities into temp table. This table exists only in the current connection. /// by default, the table is named after the data type specified. /// /// Open SqlConnection @@ -96,11 +96,9 @@ public static void BulkInsertIntoTempTable(this SqlConnection connection, Type t { tempTableName="#"+tempTableName.Replace("#",String.Empty); - //var tableName = TableMapper.GetTableName(type); var allProperties = PropertiesCache.TypePropertiesCache(type); var computedProperties = PropertiesCache.ComputedPropertiesCache(type); var insertProperties = allProperties.Except(computedProperties).ToList(); - var dataTable= ToDataTable(data, insertProperties); From 33488f704594cf642b15b2ea0aaeb344e63352c6 Mon Sep 17 00:00:00 2001 From: Andrey Khvan <83340755+andrewkhvan@users.noreply.github.com> Date: Sat, 30 Oct 2021 23:42:07 +0600 Subject: [PATCH 3/3] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 43522aa..613cb55 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,13 @@ var inserted = connection.BulkInsertAndSelect(data); ```csharp var inserted = await connection.BulkInsertAndSelectAsync(data); ``` +* Inserts entities into temp table: + +```csharp +connection.BulkInsertIntoTempTable(data,"#mytemptable"); +var data2=connection.Query("select * from #mytemptable"); +``` + `Default Conventions` ------- @@ -136,4 +143,4 @@ private class CustomColumnName [Write(false)] // Will be ignored for inserts public int Ignored { get; set; } } -``` \ No newline at end of file +```