Skip to content
Open
Show file tree
Hide file tree
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
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeOfdata>("select * from #mytemptable");
```


`Default Conventions`
-------
Expand Down Expand Up @@ -136,4 +143,4 @@ private class CustomColumnName
[Write(false)] // Will be ignored for inserts
public int Ignored { get; set; }
}
```
```
143 changes: 142 additions & 1 deletion src/Dapper.Bulk/DapperBulk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,99 @@ public static void BulkInsert(this SqlConnection connection, Type type, IEnumera
DROP TABLE {tempToBeInserted};", null, transaction);
}


/// <summary>
/// Inserts entities into temp table. This table exists only in the current connection.
/// by default, the table is named after the data type specified.
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="type">The type being inserted.</param>
/// <param name="data">Entities to insert</param>
/// <param name="tempTableName">Entities to insert</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 BulkInsertIntoTempTable(this SqlConnection connection, Type type, IEnumerable<object> 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);

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());
}

}


/// <summary>
/// Inserts entities into temp table. This table exists only in the current connection.
/// </summary>
/// <typeparam name="T">The type being inserted.</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="data">Entities to insert</param>
/// <param name="tempTableName">Temp table name</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 BulkInsertIntoTempTable<T>(this SqlConnection connection, IEnumerable<T> data,string tempTableName, SqlTransaction transaction = null, int batchSize = 0, int bulkCopyTimeout = 30)
{
var type = typeof(T);
BulkInsertIntoTempTable(connection, type, data.Cast<object>(), tempTableName, transaction, batchSize, bulkCopyTimeout);
}


/// <summary>
/// Inserts entities into temp table. This table exists only in the current connection.
/// by default, the table is named after the data type specified.
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="type">The type being inserted.</param>
/// <param name="data">Entities to insert</param>
/// <param name="tempTableName">Entities to insert</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 async static Task BulkInsertIntoTempTableAsync(this SqlConnection connection, Type type, IEnumerable<object> 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());
}

}

/// <summary>
/// Inserts entities into table <typeparamref name="T"/>s (by default) returns inserted entities.
/// </summary>
Expand Down Expand Up @@ -310,7 +403,55 @@ private static DataTable ToDataTable<T>(IEnumerable<T> data, IList<PropertyInfo>

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))
Expand Down
100 changes: 100 additions & 0 deletions tests/Dapper.Bulk.Tests/TempTableTests.cs
Original file line number Diff line number Diff line change
@@ -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<TempTableMap>();
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<AnEnum>()[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<TempTableMap>("select * from #temp1").ToList();
for(var i=0;i<tempTable.Count();i++)
{
data[i].IntField.Should().Be(tempTable[i].IntField);
data[i].LongField.Should().Be(tempTable[i].LongField);
data[i].StringField.Should().Be(tempTable[i].StringField);
data[i].BoolField.Should().Be(tempTable[i].BoolField);
data[i].ByteField.Should().Be(tempTable[i].ByteField);
data[i].DateTimeField.Should().Be(tempTable[i].DateTimeField);
data[i].EnumField.Should().Be(tempTable[i].EnumField);
data[i].StringField.Should().Be(tempTable[i].StringField);
data[i].CharleField.Should().Be(tempTable[i].CharleField);
data[i].DoubleField.Should().Be(tempTable[i].DoubleField);
data[i].FloatField.Should().Be(tempTable[i].FloatField);
data[i].SByteField.Should().Be(tempTable[i].SByteField);
data[i].ShortField.Should().Be(tempTable[i].ShortField);
data[i].UintField.Should().Be(tempTable[i].UintField);
data[i].ULongField.Should().Be(tempTable[i].ULongField);


}

}
}


}
}