Skip to content

Commit

Permalink
Fixed table name not escaped when needed #7.
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Kostov committed Jan 18, 2019
1 parent c8b2d8d commit bcb9af2
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/Dapper.Bulk.Shared/TableMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal static string GetTableName(Type type)
name = type.IsInterface && type.Name.StartsWith("I")
? type.Name.Substring(1)
: type.Name;
name = _prefix + name + _suffix;
name = $"{_prefix}{name}{_suffix}";
}

TableNames[type.TypeHandle] = name;
Expand Down
8 changes: 4 additions & 4 deletions src/Dapper.Bulk/Dapper.Bulk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
<PackageTags>fast;bulk;insert;dapper;orm;sql;micro-orm;</PackageTags>
<Copyright>Martin Kostov</Copyright>
<Description>Fast bulk insert extensions for Dapper.</Description>
<PackageReleaseNotes>-Added custom column names support.</PackageReleaseNotes>
<PackageReleaseNotes>-Fixed issue #7.</PackageReleaseNotes>
<Company>Mk</Company>
<AssemblyVersion>1.4.0.0</AssemblyVersion>
<FileVersion>1.4.0.0</FileVersion>
<Version>1.4.0</Version>
<AssemblyVersion>1.4.1.0</AssemblyVersion>
<FileVersion>1.4.1.0</FileVersion>
<Version>1.4.1</Version>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

Expand Down
44 changes: 22 additions & 22 deletions src/Dapper.Bulk/DapperBulk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ public static void BulkInsert<T>(this SqlConnection connection, IEnumerable<T> d

var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
var allPropertiesExceptKeyAndComputedString = GetColumnsStringSqlServer(allPropertiesExceptKeyAndComputed, columns);
var tempToBeInserted = $"#{tableName}_TempInsert".Replace(".", string.Empty);
var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);

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

using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BulkCopyTimeout = bulkCopyTimeout;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = tempToBeInserted;
bulkCopy.WriteToServer(ToDataTable(data, tableName, allPropertiesExceptKeyAndComputed).CreateDataReader());
bulkCopy.WriteToServer(ToDataTable(data, allPropertiesExceptKeyAndComputed).CreateDataReader());
}

connection.Execute($@"
INSERT INTO {tableName}({allPropertiesExceptKeyAndComputedString})
INSERT INTO [{tableName}]({allPropertiesExceptKeyAndComputedString})
SELECT {allPropertiesExceptKeyAndComputedString} FROM {tempToBeInserted}
DROP TABLE {tempToBeInserted};", null, transaction);
Expand Down Expand Up @@ -85,29 +85,29 @@ public static IEnumerable<T> BulkInsertAndSelect<T>(this SqlConnection connectio
var allPropertiesExceptKeyAndComputedString = GetColumnsStringSqlServer(allPropertiesExceptKeyAndComputed, columns);
var allPropertiesString = GetColumnsStringSqlServer(allProperties, columns, "target.");

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

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

using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BulkCopyTimeout = bulkCopyTimeout;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = tempToBeInserted;
bulkCopy.WriteToServer(ToDataTable(data, tableName, allPropertiesExceptKeyAndComputed).CreateDataReader());
bulkCopy.WriteToServer(ToDataTable(data, allPropertiesExceptKeyAndComputed).CreateDataReader());
}

var table = string.Join(", ", keyProperties.Select(k => $"[{k.Name }] bigint"));
var joinOn = string.Join(" AND ", keyProperties.Select(k => $"target.[{k.Name }] = ins.[{k.Name }]"));
return connection.Query<T>($@"
DECLARE {tempInsertedWithIdentity} TABLE ({table})
INSERT INTO {tableName}({allPropertiesExceptKeyAndComputedString})
INSERT INTO [{tableName}]({allPropertiesExceptKeyAndComputedString})
OUTPUT {keyPropertiesInsertedString} INTO {tempInsertedWithIdentity} ({keyPropertiesString})
SELECT {allPropertiesExceptKeyAndComputedString} FROM {tempToBeInserted}
SELECT {allPropertiesString}
FROM {tableName} target INNER JOIN {tempInsertedWithIdentity} ins ON {joinOn}
FROM [{tableName}] target INNER JOIN {tempInsertedWithIdentity} ins ON {joinOn}
DROP TABLE {tempToBeInserted};", null, transaction);
}
Expand All @@ -132,20 +132,20 @@ public static async Task BulkInsertAsync<T>(this SqlConnection connection, IEnum

var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
var allPropertiesExceptKeyAndComputedString = GetColumnsStringSqlServer(allPropertiesExceptKeyAndComputed,columns);
var tempToBeInserted = $"#{tableName}_TempInsert".Replace(".", string.Empty);
var tempToBeInserted = $"#TempInsert_{tableName}".Replace(".", string.Empty);

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

using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BulkCopyTimeout = bulkCopyTimeout;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = tempToBeInserted;
await bulkCopy.WriteToServerAsync(ToDataTable(data, tableName, allPropertiesExceptKeyAndComputed).CreateDataReader());
await bulkCopy.WriteToServerAsync(ToDataTable(data, allPropertiesExceptKeyAndComputed).CreateDataReader());
}

await connection.ExecuteAsync($@"
INSERT INTO {tableName}({allPropertiesExceptKeyAndComputedString})
INSERT INTO [{tableName}]({allPropertiesExceptKeyAndComputedString})
SELECT {allPropertiesExceptKeyAndComputedString} FROM {tempToBeInserted}
DROP TABLE {tempToBeInserted};", null, transaction);
Expand Down Expand Up @@ -184,29 +184,29 @@ public static async Task<IEnumerable<T>> BulkInsertAndSelectAsync<T>(this SqlCon
var allPropertiesExceptKeyAndComputedString = GetColumnsStringSqlServer(allPropertiesExceptKeyAndComputed,columns);
var allPropertiesString = GetColumnsStringSqlServer(allProperties, columns, "target.");

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

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

using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BulkCopyTimeout = bulkCopyTimeout;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = tempToBeInserted;
await bulkCopy.WriteToServerAsync(ToDataTable(data, tableName, allPropertiesExceptKeyAndComputed).CreateDataReader());
await bulkCopy.WriteToServerAsync(ToDataTable(data, allPropertiesExceptKeyAndComputed).CreateDataReader());
}

var table = string.Join(", ", keyProperties.Select(k => $"[{k.Name }] bigint"));
var joinOn = string.Join(" AND ", keyProperties.Select(k => $"target.[{k.Name }] = ins.[{k.Name }]"));
return await connection.QueryAsync<T>($@"
DECLARE {tempInsertedWithIdentity} TABLE ({table})
INSERT INTO {tableName}({allPropertiesExceptKeyAndComputedString})
INSERT INTO [{tableName}]({allPropertiesExceptKeyAndComputedString})
OUTPUT {keyPropertiesInsertedString} INTO {tempInsertedWithIdentity} ({keyPropertiesString})
SELECT {allPropertiesExceptKeyAndComputedString} FROM {tempToBeInserted}
SELECT {allPropertiesString}
FROM {tableName} target INNER JOIN {tempInsertedWithIdentity} ins ON {joinOn}
FROM [{tableName}] target INNER JOIN {tempInsertedWithIdentity} ins ON {joinOn}
DROP TABLE {tempToBeInserted};", null, transaction);
}
Expand All @@ -221,9 +221,9 @@ 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, string tableName, IList<PropertyInfo> properties)
private static DataTable ToDataTable<T>(IEnumerable<T> data, IList<PropertyInfo> properties)
{
var dataTable = new DataTable(tableName);
var dataTable = new DataTable();
foreach (var prop in properties)
{
dataTable.Columns.Add(prop.Name);
Expand Down
49 changes: 49 additions & 0 deletions tests/Dapper.Bulk.Tests/EscapeTableNameTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using FluentAssertions;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Xunit;

namespace Dapper.Bulk.Tests
{
public class EscapeTableNameTests : SqlServerTestSuite
{
[Table("10_Escapes")]
private class Escape
{
public int Id { get; set; }

[Column("10_Name")]
public string Name { get; set; }
}

[Fact]
public void EscapesTest()
{
var data = new List<Escape>();
for (var i = 0; i < 10; i++)
{
data.Add(new Escape {
Id = i,
Name = i.ToString()
});
}

using (var connection = this.GetConnection())
{
connection.Open();
var inserted = connection.BulkInsertAndSelect(data).ToList();
for (var i = 0; i < data.Count; i++)
{
IsValidInsert(inserted[i], data[i]);
}
}
}

private static void IsValidInsert(Escape inserted, Escape toBeInserted)
{
inserted.Id.Should().BePositive();
inserted.Name.Should().Be(toBeInserted.Name);
}
}
}
8 changes: 7 additions & 1 deletion tests/Dapper.Bulk.Tests/SqlServerTestSuite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ [IdKey] BIGINT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(100) NULL
);");


connection.Execute(
$@"{DropTable("CustomColumnNames")}
CREATE TABLE CustomColumnNames
Expand All @@ -56,6 +55,13 @@ [Name_1] NVARCHAR(100) NULL,
[Int_Col] INT NOT NULL,
[Long_Col] BIGINT NOT NULL
);");

connection.Execute(
$@"{DropTable("10_Escapes")}
CREATE TABLE [10_Escapes](
[Id] BIGINT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[10_Name] NVARCHAR(100) NULL
);");
}
}
}
Expand Down

0 comments on commit bcb9af2

Please sign in to comment.