Skip to content

Commit f6286cc

Browse files
authored
Merge pull request #1167 from mikependon/repodb-optimized-batch-statements
Repodb optimized batch statements
2 parents feabab1 + ed70bf7 commit f6286cc

File tree

7 files changed

+305
-181
lines changed

7 files changed

+305
-181
lines changed

RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/StatementBuilders/CreateInsertAllTest.cs

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ public void TestBaseStatementBuilderCreateInsertAll()
4040
var expected = $"" +
4141
$"INSERT INTO [Table] " +
4242
$"( [Field1], [Field2], [Field3] ) " +
43-
$"VALUES " +
44-
$"( @Field1, @Field2, @Field3 ) ;";
43+
$"SELECT [Field1], [Field2], [Field3] " +
44+
$"FROM ( " +
45+
$"VALUES ( @Field1, @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) " +
46+
$") AS T " +
47+
$"( [Field1], [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
48+
$"ORDER BY [__RepoDb_OrderColumn] ;";
4549

4650
// Assert
4751
Assert.AreEqual(expected, actual);
@@ -64,8 +68,13 @@ public void TestBaseStatementBuilderCreateInsertAllWithQuotedTableSchema()
6468
var expected = $"" +
6569
$"INSERT INTO [dbo].[Table] " +
6670
$"( [Field1], [Field2], [Field3] ) " +
67-
$"VALUES " +
68-
$"( @Field1, @Field2, @Field3 ) ;";
71+
$"SELECT [Field1], [Field2], [Field3] " +
72+
$"FROM " +
73+
$"( " +
74+
$"VALUES ( @Field1, @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) " +
75+
$") AS T " +
76+
$"( [Field1], [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
77+
$"ORDER BY [__RepoDb_OrderColumn] ;";
6978

7079
// Assert
7180
Assert.AreEqual(expected, actual);
@@ -88,8 +97,14 @@ public void TestBaseStatementBuilderCreateInsertAllWithUnquotedTableSchema()
8897
var expected = $"" +
8998
$"INSERT INTO [dbo].[Table] " +
9099
$"( [Field1], [Field2], [Field3] ) " +
100+
$"SELECT [Field1], [Field2], [Field3] " +
101+
$"FROM " +
102+
$"( " +
91103
$"VALUES " +
92-
$"( @Field1, @Field2, @Field3 ) ;";
104+
$"( @Field1, @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) " +
105+
$") AS T " +
106+
$"( [Field1], [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
107+
$"ORDER BY [__RepoDb_OrderColumn] ;";
93108

94109
// Assert
95110
Assert.AreEqual(expected, actual);
@@ -113,8 +128,14 @@ public void TestBaseStatementBuilderCreateInsertAllWithPrimary()
113128
var expected = $"" +
114129
$"INSERT INTO [Table] " +
115130
$"( [Field1], [Field2], [Field3] ) " +
131+
$"SELECT [Field1], [Field2], [Field3] " +
132+
$"FROM " +
133+
$"( " +
116134
$"VALUES " +
117-
$"( @Field1, @Field2, @Field3 ) ;";
135+
$"( @Field1, @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) " +
136+
$") AS T " +
137+
$"( [Field1], [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
138+
$"ORDER BY [__RepoDb_OrderColumn] ;";
118139

119140
// Assert
120141
Assert.AreEqual(expected, actual);
@@ -138,16 +159,15 @@ public void TestBaseStatementBuilderCreateInsertAllForThreeBatches()
138159
var expected = $"" +
139160
$"INSERT INTO [Table] " +
140161
$"( [Field2], [Field3] ) " +
162+
$"SELECT [Field2], [Field3] " +
163+
$"FROM ( " +
141164
$"VALUES " +
142-
$"( @Field2, @Field3 ) ; " +
143-
$"INSERT INTO [Table] " +
144-
$"( [Field2], [Field3] ) " +
145-
$"VALUES " +
146-
$"( @Field2_1, @Field3_1 ) ; " +
147-
$"INSERT INTO [Table] " +
148-
$"( [Field2], [Field3] ) " +
149-
$"VALUES " +
150-
$"( @Field2_2, @Field3_2 ) ;";
165+
$"( @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) , " +
166+
$"( @Field2_1, @Field3_1 , @__RepoDb_OrderColumn_1 ) , " +
167+
$"( @Field2_2, @Field3_2 , @__RepoDb_OrderColumn_2 ) " +
168+
$") AS T " +
169+
$"( [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
170+
$"ORDER BY [__RepoDb_OrderColumn] ;";
151171

152172
// Assert
153173
Assert.AreEqual(expected, actual);
@@ -171,8 +191,14 @@ public void TestBaseStatementBuilderCreateInsertAllWithHints()
171191
var expected = $"" +
172192
$"INSERT INTO [Table] WITH (TABLOCK) " +
173193
$"( [Field1], [Field2], [Field3] ) " +
194+
$"SELECT [Field1], [Field2], [Field3] " +
195+
$"FROM ( " +
174196
$"VALUES " +
175-
$"( @Field1, @Field2, @Field3 ) ;";
197+
$"( " +
198+
$"@Field1, @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) " +
199+
$") AS T " +
200+
$"( [Field1], [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
201+
$"ORDER BY [__RepoDb_OrderColumn] ;";
176202

177203
// Assert
178204
Assert.AreEqual(expected, actual);
@@ -197,16 +223,15 @@ public void TestBaseStatementBuilderCreateInsertAllForThreeBatchesWithHints()
197223
var expected = $"" +
198224
$"INSERT INTO [Table] WITH (TABLOCK) " +
199225
$"( [Field2], [Field3] ) " +
226+
$"SELECT [Field2], [Field3] " +
227+
$"FROM ( " +
200228
$"VALUES " +
201-
$"( @Field2, @Field3 ) ; " +
202-
$"INSERT INTO [Table] WITH (TABLOCK) " +
203-
$"( [Field2], [Field3] ) " +
204-
$"VALUES " +
205-
$"( @Field2_1, @Field3_1 ) ; " +
206-
$"INSERT INTO [Table] WITH (TABLOCK) " +
207-
$"( [Field2], [Field3] ) " +
208-
$"VALUES " +
209-
$"( @Field2_2, @Field3_2 ) ;";
229+
$"( @Field2, @Field3 , @__RepoDb_OrderColumn_0 ) , " +
230+
$"( @Field2_1, @Field3_1 , @__RepoDb_OrderColumn_1 ) , " +
231+
$"( @Field2_2, @Field3_2 , @__RepoDb_OrderColumn_2 ) " +
232+
$") AS T " +
233+
$"( [Field2], [Field3] , [__RepoDb_OrderColumn] ) " +
234+
$"ORDER BY [__RepoDb_OrderColumn] ;";
210235

211236
// Assert
212237
Assert.AreEqual(expected, actual);

RepoDb.Core/RepoDb/Operations/DbConnection/InsertAll.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -597,18 +597,16 @@ internal static int InsertAllInternalBase<TEntity>(this IDbConnection connection
597597

598598
// Get the results
599599
var position = 0;
600-
do
600+
while (reader.Read())
601601
{
602-
if (reader.Read())
603-
{
604-
var value = Converter.DbNullToNull(reader.GetValue(0));
605-
var index = batchItems.Count > 1 && reader.FieldCount > 1 ? reader.GetInt32(1) : position;
606-
context.KeyPropertySetterFunc.Invoke(batchItems[index], value);
607-
result++;
608-
}
602+
var value = Converter.DbNullToNull(reader.GetValue(0));
603+
var index = batchItems.Count > 1 && reader.FieldCount > 1 ? reader.GetInt32(1) : position;
604+
context.KeyPropertySetterFunc.Invoke(batchItems[index], value);
609605
position++;
610606
}
611-
while (reader.NextResult());
607+
608+
// Set the result
609+
result += batchItems.Count;
612610

613611
// After Execution
614612
Tracer
@@ -841,19 +839,16 @@ await Tracer
841839

842840
// Get the results
843841
var position = 0;
844-
do
842+
while (await reader.ReadAsync(cancellationToken))
845843
{
846-
if (await reader.ReadAsync(cancellationToken))
847-
{
848-
// No need to use async on this level (await reader.GetFieldValueAsync<object>(0, cancellationToken))
849-
var value = Converter.DbNullToNull(reader.GetValue(0));
850-
var index = batchItems.Count > 1 && reader.FieldCount > 1 ? reader.GetInt32(1) : position;
851-
context.KeyPropertySetterFunc.Invoke(batchItems[index], value);
852-
result++;
853-
}
844+
var value = Converter.DbNullToNull(reader.GetValue(0));
845+
var index = batchItems.Count > 1 && reader.FieldCount > 1 ? reader.GetInt32(1) : position;
846+
context.KeyPropertySetterFunc.Invoke(batchItems[index], value);
854847
position++;
855848
}
856-
while (await reader.NextResultAsync(cancellationToken));
849+
850+
// Set the result
851+
result += batchItems.Count;
857852

858853
// After Execution
859854
await Tracer

RepoDb.Core/RepoDb/StatementBuilders/BaseStatementBuilder.cs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using RepoDb.Exceptions;
77
using RepoDb.Enumerations;
8+
using System.Reflection;
89

910
namespace RepoDb.StatementBuilders
1011
{
@@ -466,23 +467,51 @@ public virtual string CreateInsertAll(string tableName,
466467
// Build the query
467468
builder.Clear();
468469

470+
// Compose
471+
builder
472+
.Insert()
473+
.Into()
474+
.TableNameFrom(tableName, DbSetting)
475+
.HintsFrom(hints)
476+
.OpenParen()
477+
.FieldsFrom(insertableFields, DbSetting)
478+
.CloseParen()
479+
.Select()
480+
.FieldsFrom(insertableFields, DbSetting)
481+
.From()
482+
.OpenParen()
483+
.Values();
484+
469485
// Iterate the indexes
470486
for (var index = 0; index < batchSize; index++)
471487
{
472-
builder.Insert()
473-
.Into()
474-
.TableNameFrom(tableName, DbSetting)
475-
.HintsFrom(hints)
476-
.OpenParen()
477-
.FieldsFrom(insertableFields, DbSetting)
478-
.CloseParen()
479-
.Values()
488+
builder
480489
.OpenParen()
481490
.ParametersFrom(insertableFields, index, DbSetting)
482-
.CloseParen()
483-
.End();
491+
.WriteText(
492+
string.Concat(", ",
493+
$"{DbSetting.ParameterPrefix}__RepoDb_OrderColumn_{index}"))
494+
.CloseParen();
495+
496+
if (index < batchSize - 1)
497+
{
498+
builder
499+
.WriteText(",");
500+
}
484501
}
485502

503+
// Close
504+
builder
505+
.CloseParen()
506+
.As("T")
507+
.OpenParen()
508+
.FieldsFrom(insertableFields, DbSetting)
509+
.WriteText(string.Concat(", ", "__RepoDb_OrderColumn".AsQuoted(DbSetting)))
510+
.CloseParen()
511+
.OrderBy()
512+
.WriteText("__RepoDb_OrderColumn".AsQuoted(DbSetting))
513+
.End();
514+
486515
// Return the query
487516
return builder.GetString();
488517
}

RepoDb.PostgreSql/RepoDb.PostgreSql.UnitTests/StatementBuilderTest.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,11 @@ public void TestPostgreSqlStatementBuilderCreateInsertAll()
309309
3,
310310
null,
311311
null);
312-
var expected = "INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id, @Name, @Address ) RETURNING NULL AS \"Result\", @__RepoDb_OrderColumn_0 AS \"OrderColumn\" ; " +
313-
"INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id_1, @Name_1, @Address_1 ) RETURNING NULL AS \"Result\", @__RepoDb_OrderColumn_1 AS \"OrderColumn\" ; " +
314-
"INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id_2, @Name_2, @Address_2 ) RETURNING NULL AS \"Result\", @__RepoDb_OrderColumn_2 AS \"OrderColumn\" ;";
312+
var expected = "INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) " +
313+
"VALUES " +
314+
"( @Id, @Name, @Address ) , " +
315+
"( @Id_1, @Name_1, @Address_1 ) , " +
316+
"( @Id_2, @Name_2, @Address_2 ) ;";
315317

316318
// Assert
317319
Assert.AreEqual(expected, query);
@@ -329,9 +331,12 @@ public void TestPostgreSqlStatementBuilderCreateInserAlltWithPrimary()
329331
3,
330332
new DbField("Id", true, false, false, typeof(int), null, null, null, null),
331333
null);
332-
var expected = "INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id, @Name, @Address ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_0 AS \"OrderColumn\" ; " +
333-
"INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id_1, @Name_1, @Address_1 ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_1 AS \"OrderColumn\" ; " +
334-
"INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) VALUES ( @Id_2, @Name_2, @Address_2 ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_2 AS \"OrderColumn\" ;";
334+
var expected = "INSERT INTO \"Table\" ( \"Id\", \"Name\", \"Address\" ) " +
335+
"VALUES " +
336+
"( @Id, @Name, @Address ) , " +
337+
"( @Id_1, @Name_1, @Address_1 ) , " +
338+
"( @Id_2, @Name_2, @Address_2 ) " +
339+
"RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\" ;";
335340

336341
// Assert
337342
Assert.AreEqual(expected, query);
@@ -349,9 +354,12 @@ public void TestPostgreSqlStatementBuilderCreateInsertAllWithIdentity()
349354
3,
350355
null,
351356
new DbField("Id", false, true, false, typeof(int), null, null, null, null));
352-
var expected = "INSERT INTO \"Table\" ( \"Name\", \"Address\" ) VALUES ( @Name, @Address ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_0 AS \"OrderColumn\" ; " +
353-
"INSERT INTO \"Table\" ( \"Name\", \"Address\" ) VALUES ( @Name_1, @Address_1 ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_1 AS \"OrderColumn\" ; " +
354-
"INSERT INTO \"Table\" ( \"Name\", \"Address\" ) VALUES ( @Name_2, @Address_2 ) RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\", @__RepoDb_OrderColumn_2 AS \"OrderColumn\" ;";
357+
var expected = "INSERT INTO \"Table\" ( \"Name\", \"Address\" ) " +
358+
"VALUES " +
359+
"( @Name, @Address ) , " +
360+
"( @Name_1, @Address_1 ) , " +
361+
"( @Name_2, @Address_2 ) " +
362+
"RETURNING CAST(\"Id\" AS INTEGER) AS \"Result\" ;";
355363

356364
// Assert
357365
Assert.AreEqual(expected, query);

0 commit comments

Comments
 (0)