Skip to content

Commit 0644b4b

Browse files
Improve tests (#41)
* Fix tests. * Drop table. * another fix. * Fix tests
1 parent bc05f0b commit 0644b4b

15 files changed

Lines changed: 315 additions & 286 deletions

File tree

src/PhenX.EntityFrameworkCore.BulkInsert.Sqlite/SqliteBulkInsertProvider.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ internal class SqliteBulkInsertProvider(ILogger<SqliteBulkInsertProvider>? logge
2020
/// <inheritdoc />
2121
protected override string BulkInsertId => "rowid";
2222

23-
//language=sql
2423
/// <inheritdoc />
2524
protected override string AddTableCopyBulkInsertId => "--"; // No need to add an ID column in SQLite
2625

26+
/// <inheritdoc />
27+
protected override string GetTempTableName(string tableName) => $"_temp_bulk_insert_test_entity_{Guid.NewGuid():N}";
28+
2729
/// <inheritdoc />
2830
protected override BulkInsertOptions CreateDefaultOptions() => new()
2931
{
@@ -116,6 +118,12 @@ private static DbCommand GetInsertCommand(
116118
return command;
117119
}
118120

121+
/// <inheritdoc />
122+
protected override Task DropTempTableAsync(bool sync, DbContext dbContext, string tableName)
123+
{
124+
return ExecuteAsync(sync, dbContext, $"DROP TABLE IF EXISTS {tableName}", default);
125+
}
126+
119127
/// <inheritdoc />
120128
protected override async Task BulkInsert<T>(
121129
bool sync,

src/PhenX.EntityFrameworkCore.BulkInsert/BulkInsertProviderBase.cs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Runtime.CompilerServices;
2+
using System.Runtime.InteropServices;
23

34
using Microsoft.EntityFrameworkCore;
45
using Microsoft.EntityFrameworkCore.Storage;
@@ -43,14 +44,20 @@ protected override async IAsyncEnumerable<T> BulkInsertReturnEntities<T>(
4344
}
4445

4546
var tableName = await PerformBulkInsertAsync(sync, context, tableInfo, entities, options, tempTableRequired: true, ctk: ctk);
47+
try
48+
{
49+
var result =
50+
await CopyFromTempTableAsync<T, T>(sync, context, tableInfo, tableName, true, options, onConflict, ctk: ctk)
51+
?? throw new InvalidOperationException("Copy returns null enumerable.");
4652

47-
var result =
48-
await CopyFromTempTableAsync<T, T>(sync, context, tableInfo, tableName, true, options, onConflict, ctk: ctk)
49-
?? throw new InvalidOperationException("Copy returns null enumerable.");
50-
51-
await foreach (var item in result.WithCancellation(ctk))
53+
await foreach (var item in result.WithCancellation(ctk))
54+
{
55+
yield return item;
56+
}
57+
}
58+
finally
5259
{
53-
yield return item;
60+
await PerformDropTempTableAsync(sync, context, tableName);
5461
}
5562

5663
// Commit the transaction if we own them.
@@ -71,6 +78,11 @@ protected override async Task BulkInsert<T>(
7178
OnConflictOptions<T>? onConflict,
7279
CancellationToken ctk) where T : class
7380
{
81+
if (entities.TryGetNonEnumeratedCount(out var count) && count == 0)
82+
{
83+
throw new InvalidOperationException("No entities to insert.");
84+
}
85+
7486
using var activity = Telemetry.ActivitySource.StartActivity("BulkInsert");
7587
activity?.AddTag("tableName", tableInfo.TableName);
7688
activity?.AddTag("synchronous", sync);
@@ -86,8 +98,14 @@ protected override async Task BulkInsert<T>(
8698
}
8799

88100
var tableName = await PerformBulkInsertAsync(sync, context, tableInfo, entities, options, tempTableRequired: true, ctk: ctk);
89-
90-
await CopyFromTempTableAsync<T, T>(sync, context, tableInfo, tableName, false, options, onConflict, ctk);
101+
try
102+
{
103+
await CopyFromTempTableAsync<T, T>(sync, context, tableInfo, tableName, false, options, onConflict, ctk);
104+
}
105+
finally
106+
{
107+
await PerformDropTempTableAsync(sync, context, tableName);
108+
}
91109
}
92110
else
93111
{
@@ -107,7 +125,6 @@ protected override async Task BulkInsert<T>(
107125
await connection.Close(sync, ctk);
108126
}
109127
}
110-
111128
private async Task<string> PerformBulkInsertAsync<T>(
112129
bool sync,
113130
DbContext context,
@@ -117,11 +134,6 @@ private async Task<string> PerformBulkInsertAsync<T>(
117134
bool tempTableRequired,
118135
CancellationToken ctk) where T : class
119136
{
120-
if (entities.TryGetNonEnumeratedCount(out var count) && count == 0)
121-
{
122-
throw new InvalidOperationException("No entities to insert.");
123-
}
124-
125137
var tableName = tempTableRequired
126138
? await CreateTableCopyAsync<T>(sync, context, options, tableInfo, ctk)
127139
: tableInfo.QuotedTableName;
@@ -208,6 +220,33 @@ protected virtual async Task AddBulkInsertIdColumn<T>(
208220
return null;
209221
}
210222

223+
private async Task PerformDropTempTableAsync(bool sync, DbContext dbContext, string tableName)
224+
{
225+
try
226+
{
227+
await DropTempTableAsync(sync, dbContext, tableName);
228+
}
229+
catch (Exception ex)
230+
{
231+
// The drop operation is not mandatory, therefore never fail the actual operation.
232+
if (logger != null)
233+
{
234+
Log.DropTemporaryTableFailed(logger, ex);
235+
}
236+
}
237+
}
238+
239+
/// <summary>
240+
/// Drops the temporary table manually if needed.
241+
/// </summary>
242+
/// <param name="sync">Indicates if the operation is synchronous.</param>
243+
/// <param name="dbContext">The context.</param>
244+
/// <param name="tableName">The table name.</param>
245+
protected virtual Task DropTempTableAsync(bool sync, DbContext dbContext, string tableName)
246+
{
247+
return Task.CompletedTask;
248+
}
249+
211250
protected static async Task ExecuteAsync(
212251
bool sync,
213252
DbContext context,

src/PhenX.EntityFrameworkCore.BulkInsert/BulkInsertProviderUntyped.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public IAsyncEnumerable<T> BulkInsertReturnEntities<T>(
3636
throw new InvalidOperationException($"Invalid options type: {options.GetType().Name}. Expected: {typeof(TOptions).Name}");
3737
}
3838

39+
if (entities.TryGetNonEnumeratedCount(out var count) && count == 0)
40+
{
41+
throw new InvalidOperationException("No entities to insert.");
42+
}
43+
3944
return BulkInsertReturnEntities(sync, context, tableInfo, entities, providerOptions, onConflict, ctk);
4045
}
4146

@@ -62,6 +67,11 @@ public Task BulkInsert<T>(
6267
throw new InvalidOperationException($"Invalid options type: {options.GetType().Name}. Expected: {typeof(TOptions).Name}");
6368
}
6469

70+
if (entities.TryGetNonEnumeratedCount(out var count) && count == 0)
71+
{
72+
throw new InvalidOperationException("No entities to insert.");
73+
}
74+
6575
return BulkInsert(sync, context, tableInfo, entities, providerOptions, onConflict, ctk);
6676
}
6777

src/PhenX.EntityFrameworkCore.BulkInsert/Dialect/SqlDialectBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public virtual string BuildMoveDataSql<T>(
8484

8585
if (returnedColumns.Count != 0)
8686
{
87-
q.Append("RETURNING ");
87+
q.Append(" RETURNING ");
8888
q.AppendJoin(", ", returnedColumns.Select(p => p.QuotedColumName));
8989
q.AppendLine();
9090
}

src/PhenX.EntityFrameworkCore.BulkInsert/Log.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ internal static partial class Log
2121
Level = LogLevel.Trace,
2222
Message = "Insert to table directly")]
2323
public static partial void UsingDirectInsert(ILogger logger);
24+
25+
[LoggerMessage(
26+
EventId = 1003,
27+
Level = LogLevel.Error,
28+
Message = "Failed to drop temporary table.")]
29+
public static partial void DropTemporaryTableFailed(ILogger logger, Exception exception);
2430
}

tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/DbContext/TestEntity.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
88
[PrimaryKey(nameof(Id))]
99
[Index(nameof(Name), IsUnique = true)]
1010
[Table("test_entity")]
11-
public class TestEntity
11+
public class TestEntity : TestEntityBase
1212
{
1313
public int Id { get; set; }
1414

@@ -19,9 +19,6 @@ public class TestEntity
1919
[Column("some_price")]
2020
public decimal Price { get; set; }
2121

22-
[Column("test_run")]
23-
public Guid TestRun { get; set; }
24-
2522
[Column("the_identifier")]
2623
public Guid Identifier { get; set; }
2724

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.ComponentModel.DataAnnotations.Schema;
2+
3+
namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
4+
5+
public abstract class TestEntityBase
6+
{
7+
[Column("test_run")]
8+
public Guid TestRun { get; set; }
9+
}

tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/DbContext/TestEntityWithConverters.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
55

66
[Table("test_entity_with_converters")]
7-
public class TestEntityWithConverters
7+
public class TestEntityWithConverters : TestEntityBase
88
{
99
public int Id { get; set; }
1010

@@ -14,8 +14,5 @@ public class TestEntityWithConverters
1414

1515
[Column("created_at")]
1616
public DateTime CreatedAt { get; set; }
17-
18-
[Column("test_run")]
19-
public Guid TestRun { get; set; }
2017
}
2118

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
using System.ComponentModel.DataAnnotations;
1+
using System.ComponentModel.DataAnnotations;
22
using System.ComponentModel.DataAnnotations.Schema;
33

44
using NetTopologySuite.Geometries;
55

66
namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
77

88
[Table("test_entity_geo")]
9-
public class TestEntityWithGeo
9+
public class TestEntityWithGeo : TestEntityBase
1010
{
1111
[Key]
1212
public int Id { get; set; }
1313

1414
public Geometry GeoObject { get; set; } = null!;
15-
16-
[Column("test_run")]
17-
public Guid TestRun { get; set; }
1815
}

tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/DbContext/TestEntityWithGuidId.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@
44
namespace PhenX.EntityFrameworkCore.BulkInsert.Tests.DbContext;
55

66
[Table("test_entity_guids")]
7-
public class TestEntityWithGuidId
7+
public class TestEntityWithGuidId : TestEntityBase
88
{
99
[Key]
1010
public Guid Id { get; set; }
1111

1212
[Column("name")]
1313
[MaxLength(100)]
1414
public string Name { get; set; } = string.Empty;
15-
16-
[Column("test_run")]
17-
public Guid TestRun { get; set; }
1815
}

0 commit comments

Comments
 (0)