Skip to content

Commit

Permalink
Execute with temp table extension with object definition. (#86)
Browse files Browse the repository at this point in the history
* Support for composite primary key in bulk update.

* Set timeout to nested transaction by top transaction.

* Unit tests.

* Execute with temp table extension with object definition.

* Target framworks.

* Fix build for net4.6.

Co-authored-by: Ján Slivka <[email protected]>
  • Loading branch information
JanoSlivka and JanSlivka authored Oct 20, 2021
1 parent 779bc62 commit a320f1c
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 8 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ For this purpose exists `IValueGenerator` interface which your class must implem
```c#
public interface IValueGenerator
{
object GetValue();
object GetValue();
}
```

Expand All @@ -383,7 +383,7 @@ Here is an example of custom value generator:
```c#
private class AutoIncrementValueGenerator : IValueGenerator
{
public object GetValue() => 123;
public object GetValue() => 123;
}
```

Expand Down Expand Up @@ -777,6 +777,24 @@ _database.ExecuteWithTempTable(ids, (database, tableName)
=> database.Query<Person>()
.From($"PERSON AS P INNER JOIN {tableName} AS T ON (P.Id = T.Value)")
.ToList());

public class IdDto
{
public IdDto(int id)
{
Id = id;
}

public int Id { get; set; }
}

var ids = new List<IdDto>(){ new IdDto(0), new IdDto(1), new IdDto(2), new IdDto(3) };

_database.ExecuteWithTempTable(ids, (database, tableName)
=> database.Query<Person>()
.Select("P.*")
.From($"PERSON AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)")
.ToList());
```

### SQL commands executing
Expand Down
25 changes: 20 additions & 5 deletions src/IDatabaseExtensions.TempTable.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Kros.Data.BulkActions;
using Kros.KORM.Data;
using Kros.KORM.Extensions;
using Kros.KORM.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Kros.KORM
Expand Down Expand Up @@ -234,25 +236,38 @@ private static void InsertValuesIntoTempTable<TValue>(
IEnumerable<TValue> values,
string tempTableName)
{
database.ExecuteNonQuery($"CREATE TABLE {tempTableName} ( Value {typeof(TValue).ToSqlDataType()} )");
TableInfo tableInfo = Database.DatabaseMapper.GetTableInfo<TValue>();
string columns = GetColumnsWithSqlTypes(tableInfo, typeof(TValue));
database.ExecuteNonQuery($"CREATE TABLE {tempTableName} ( {columns} )");

using IBulkInsert bulkInsert = database.CreateBulkInsert();

bulkInsert.DestinationTableName = tempTableName;

using var reader = new EnumerableDataReader<TValue>(values, new string[] { "Value" });
using var reader = new EnumerableDataReader<TValue>(values, GetColumns(tableInfo, typeof(TValue)));

bulkInsert.Insert(reader);
}

private static string GetColumnsWithSqlTypes(TableInfo tableInfo, Type type)
=> (type.IsPrimitive || type == typeof(string))
? $"Value {type.ToSqlDataType()}"
: string.Join(
",",
tableInfo.Columns.Select(c => $"[{c.PropertyInfo.Name}] {c.PropertyInfo.PropertyType.ToSqlDataType()}"));

private static IEnumerable<string> GetColumns(TableInfo tableInfo, Type type)
=> (type.IsPrimitive || type == typeof(string))
? new string[] { "Value" }
: tableInfo.Columns.Select(c => c.PropertyInfo.Name);

private static void InsertValuesIntoTempTable<TKey, TValue>(
IDatabase database,
IDictionary<TKey, TValue> values,
string tempTableName)
{
database.ExecuteNonQuery($"CREATE TABLE {tempTableName} " +
$"( [Key] {typeof(TKey).ToSqlDataType()}, " +
$" [Value] {typeof(TValue).ToSqlDataType()} )");
database.ExecuteNonQuery(
$"CREATE TABLE {tempTableName}([Key] {typeof(TKey).ToSqlDataType()}, [Value] {typeof(TValue).ToSqlDataType()})");

using IBulkInsert bulkInsert = database.CreateBulkInsert();
bulkInsert.DestinationTableName = tempTableName;
Expand Down
2 changes: 1 addition & 1 deletion src/Kros.KORM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;net46</TargetFrameworks>
<Version>4.3.1</Version>
<Version>4.3.2</Version>
<Authors>KROS a. s.</Authors>
<Company>KROS a. s.</Company>
<Description>KORM is fast, easy to use, micro ORM tool (Kros Object Relation Mapper).</Description>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using FluentAssertions;
using Kros.Extensions;
using Kros.KORM.Metadata.Attribute;
using Kros.KORM.UnitTests.Base;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -40,6 +43,72 @@ public void ExecuteWithTempTableList()
}
}

[Fact]
public void ExecuteWithTempTableObjectList()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<IdDto> ids = CreateIds();
var affectedCount = database.ExecuteWithTempTable(
ids,
(database, tableName) => database.ExecuteNonQuery(
$@"UPDATE P
SET P.Age = 18
FROM People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)"));

affectedCount.Should().Be(4);
}
}

[Fact]
public void ExecuteWithTempTableObjectListNoMapColumnThrowException()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<TestDto> data = CreateTestData();
Action act = () => database.ExecuteWithTempTable(
data,
(database, tableName) => database.ExecuteNonQuery(
$@"UPDATE P
SET P.Age = 18
FROM People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Number)"));
act.Should().Throw<SqlException>().WithMessage("Invalid column name 'Number'.");
}
}

[Fact]
public void ExecuteWithTempTableObjectListAliasColumnThrowException()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<TestDto> data = CreateTestData();
Action act = () => database.ExecuteWithTempTable(
data,
(database, tableName) => database.ExecuteNonQuery(
$@"UPDATE P
SET P.Age = 18
FROM People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Value)"));
act.Should().Throw<SqlException>().WithMessage("Invalid column name 'Value'.");
}
}

[Fact]
public void ExecuteWithTempTableObjectListAliasColumn()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<TestDto> data = CreateTestData();
var affectedCount = database.ExecuteWithTempTable(
data,
(database, tableName) => database.ExecuteNonQuery(
$@"UPDATE P
SET P.Age = 18
FROM People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)"));

affectedCount.Should().Be(1);
}
}

[Fact]
public async Task ExecuteWithTempTableListAsync()
{
Expand All @@ -57,6 +126,23 @@ public async Task ExecuteWithTempTableListAsync()
}
}

[Fact]
public async Task ExecuteWithTempTableObjectListAsync()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<IdDto> ids = CreateIds();
var affectedCount = await database.ExecuteWithTempTableAsync(
ids,
(database, tableName) => database.ExecuteNonQueryAsync(
$@"UPDATE P
SET P.Age = 18
FROM People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)"));

affectedCount.Should().Be(4);
}
}

[Fact]
public void ExecuteWithTempTableTList()
{
Expand All @@ -72,6 +158,23 @@ public void ExecuteWithTempTableTList()
}
}

[Fact]
public void ExecuteWithTempTableTObjectList()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<IdDto> ids = CreateIds();
IEnumerable<Person> result = database.ExecuteWithTempTable(
ids,
(database, tableName) => database.Query<Person>()
.Select("P.*")
.From($"People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)")
.ToList());

result.Should().HaveCount(4);
}
}

[Fact]
public async Task ExecuteWithTempTableTListAsync()
{
Expand All @@ -89,6 +192,24 @@ public async Task ExecuteWithTempTableTListAsync()
}
}

[Fact]
public async Task ExecuteWithTempTableTObjectListAsync()
{
using (IDatabase database = CreateDatabase(CreateTable_TestTable, InsertDataScript2))
{
List<IdDto> ids = CreateIds();
IEnumerable<Person> result = await database.ExecuteWithTempTableAsync(
ids,
(database, tableName) => database.Query<Person>()
.Select("P.*")
.From($"People AS P INNER JOIN {tableName} AS T ON (P.Id = T.Id)")
.ToList()
.AsTask());

result.Should().HaveCount(4);
}
}

[Fact]
public void ExecuteWithTempTableDictionary()
{
Expand Down Expand Up @@ -175,5 +296,40 @@ await database.ExecuteNonQueryAsync(
result.Should().HaveCount(2);
}
}

private static List<IdDto> CreateIds()
=> new List<IdDto>()
{
new IdDto(1),
new IdDto(2),
new IdDto(3),
new IdDto(4),
new IdDto(456),
new IdDto(789)
};

private static List<TestDto> CreateTestData()
=> new List<TestDto>()
{
new TestDto(1, 1),
new TestDto(789, 789)
};

private record IdDto(int Id);

private class TestDto
{
public TestDto(int id, int number)
{
Id = id;
Number = number;
}

[Alias("Value")]
public int Id { get; set; }

[NoMap]
public int Number { get; set; }
}
}
}

0 comments on commit a320f1c

Please sign in to comment.