Skip to content

Commit 10ebb55

Browse files
committed
Added overloads of "BulkInsert*IntoTempTableAsync" to insert into existing temp table.
1 parent 8db9cc7 commit 10ebb55

File tree

11 files changed

+568
-15
lines changed

11 files changed

+568
-15
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Copyright>(c) $([System.DateTime]::Now.Year), Pawel Gerr. All rights reserved.</Copyright>
5-
<VersionPrefix>8.3.0</VersionPrefix>
5+
<VersionPrefix>8.4.0</VersionPrefix>
66
<Authors>Pawel Gerr</Authors>
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<PackageProjectUrl>https://dev.azure.com/pawelgerr/Thinktecture.EntityFrameworkCore</PackageProjectUrl>

src/Thinktecture.EntityFrameworkCore.BulkOperations/EntityFrameworkCore/BulkOperations/ITempTableBulkInsertExecutor.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ public interface ITempTableBulkInsertExecutor
1414
/// <returns>Options to use with <see cref="ITempTableBulkInsertExecutor"/>.</returns>
1515
ITempTableBulkInsertOptions CreateOptions(IEntityPropertiesProvider? propertiesToInsert = null);
1616

17+
/// <summary>
18+
/// Creates options with default values.
19+
/// </summary>
20+
/// <param name="propertiesToInsert">Properties to insert.</param>
21+
/// <returns>Options to use with <see cref="ITempTableBulkInsertExecutor"/>.</returns>
22+
IBulkInsertOptions CreateBulkInsertOptions(IEntityPropertiesProvider? propertiesToInsert = null);
23+
1724
/// <summary>
1825
/// Inserts the provided <paramref name="entities"/> into a temp table.
1926
/// </summary>
@@ -40,4 +47,62 @@ Task<ITempTableQuery<TColumn1>> BulkInsertValuesIntoTempTableAsync<TColumn1>(
4047
IEnumerable<TColumn1> values,
4148
ITempTableBulkInsertOptions options,
4249
CancellationToken cancellationToken);
50+
51+
/// <summary>
52+
/// Inserts the provided <paramref name="values"/> into provided <paramref name="tempTable"/>.
53+
/// </summary>
54+
/// <param name="values">Values to insert.</param>
55+
/// <param name="tempTable">Temp table to insert into.</param>
56+
/// <param name="options">Options.</param>
57+
/// <param name="cancellationToken">Cancellation token.</param>
58+
/// <typeparam name="TColumn1">Type of the values.</typeparam>
59+
Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
60+
IEnumerable<TColumn1> values,
61+
ITempTableReference tempTable,
62+
ITempTableBulkInsertOptions? options,
63+
CancellationToken cancellationToken);
64+
65+
/// <summary>
66+
/// Inserts the provided <paramref name="values"/> into provided <paramref name="tempTable"/>.
67+
/// </summary>
68+
/// <param name="values">Values to insert.</param>
69+
/// <param name="tempTable">Temp table to insert into.</param>
70+
/// <param name="options">Options.</param>
71+
/// <param name="cancellationToken">Cancellation token.</param>
72+
/// <typeparam name="TColumn1">Type of the values.</typeparam>
73+
Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
74+
IEnumerable<TColumn1> values,
75+
ITempTableReference tempTable,
76+
IBulkInsertOptions? options,
77+
CancellationToken cancellationToken);
78+
79+
/// <summary>
80+
/// Inserts the provided <paramref name="entities"/> into provided <paramref name="tempTable"/>.
81+
/// </summary>
82+
/// <param name="entities">Entities to insert.</param>
83+
/// <param name="tempTable">Temp table to insert into.</param>
84+
/// <param name="options">Options.</param>
85+
/// <param name="cancellationToken">Cancellation token.</param>
86+
/// <typeparam name="T">Type of the entities.</typeparam>
87+
Task BulkInsertIntoTempTableAsync<T>(
88+
IEnumerable<T> entities,
89+
ITempTableReference tempTable,
90+
ITempTableBulkInsertOptions? options,
91+
CancellationToken cancellationToken)
92+
where T : class;
93+
94+
/// <summary>
95+
/// Inserts the provided <paramref name="entities"/> into provided <paramref name="tempTable"/>.
96+
/// </summary>
97+
/// <param name="entities">Entities to insert.</param>
98+
/// <param name="tempTable">Temp table to insert into.</param>
99+
/// <param name="options">Options.</param>
100+
/// <param name="cancellationToken">Cancellation token.</param>
101+
/// <typeparam name="T">Type of the entities.</typeparam>
102+
Task BulkInsertIntoTempTableAsync<T>(
103+
IEnumerable<T> entities,
104+
ITempTableReference tempTable,
105+
IBulkInsertOptions? options,
106+
CancellationToken cancellationToken)
107+
where T : class;
43108
}

src/Thinktecture.EntityFrameworkCore.BulkOperations/EntityFrameworkCore/TempTables/ITempTableQuery.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@ namespace Thinktecture.EntityFrameworkCore.TempTables;
55
/// Disposal of this query will delete the corresponding temp table.
66
/// </summary>
77
/// <typeparam name="T">Type of the query item.</typeparam>
8-
public interface ITempTableQuery<out T> : IAsyncDisposable, IDisposable
8+
public interface ITempTableQuery<out T> : ITempTableReference
99
{
1010
/// <summary>
1111
/// The query itself.
1212
/// </summary>
1313
IQueryable<T> Query { get; }
14-
15-
/// <summary>
16-
/// The name of the temp table.
17-
/// </summary>
18-
string Name { get; }
1914
}

src/Thinktecture.EntityFrameworkCore.BulkOperations/Extensions/BulkOperationsDbContextExtensions.cs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,179 @@ public static Task<ITempTableQuery<T>> BulkInsertIntoTempTableAsync<T>(
293293
return executor.BulkInsertIntoTempTableAsync(entities, options, cancellationToken);
294294
}
295295

296+
/// <summary>
297+
/// Copies <paramref name="values"/> into a temp table and returns the query for accessing the inserted records.
298+
/// </summary>
299+
/// <param name="ctx">Database context.</param>
300+
/// <param name="values">Values to insert.</param>
301+
/// <param name="tempTable">Temp table to insert into.</param>
302+
/// <param name="options">Options.</param>
303+
/// <param name="cancellationToken">Cancellation token.</param>
304+
/// <typeparam name="TColumn1">Type of the values to insert.</typeparam>
305+
/// <returns>A query for accessing the inserted values.</returns>
306+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="values"/> is <c>null</c>.</exception>
307+
public static Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
308+
this DbContext ctx,
309+
IEnumerable<TColumn1> values,
310+
ITempTableReference tempTable,
311+
ITempTableBulkInsertOptions? options,
312+
CancellationToken cancellationToken = default)
313+
{
314+
ArgumentNullException.ThrowIfNull(values);
315+
316+
var executor = ctx.GetService<ITempTableBulkInsertExecutor>();
317+
318+
return executor.BulkInsertValuesIntoTempTableAsync(values, tempTable, options, cancellationToken);
319+
}
320+
321+
/// <summary>
322+
/// Copies <paramref name="values"/> into a temp table and returns the query for accessing the inserted records.
323+
/// </summary>
324+
/// <param name="ctx">Database context.</param>
325+
/// <param name="values">Values to insert.</param>
326+
/// <param name="tempTable">Temp table to insert into.</param>
327+
/// <param name="options">Options.</param>
328+
/// <param name="cancellationToken">Cancellation token.</param>
329+
/// <typeparam name="TColumn1">Type of the values to insert.</typeparam>
330+
/// <returns>A query for accessing the inserted values.</returns>
331+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="values"/> is <c>null</c>.</exception>
332+
public static Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
333+
this DbContext ctx,
334+
IEnumerable<TColumn1> values,
335+
ITempTableReference tempTable,
336+
IBulkInsertOptions? options = null,
337+
CancellationToken cancellationToken = default)
338+
{
339+
ArgumentNullException.ThrowIfNull(values);
340+
341+
var executor = ctx.GetService<ITempTableBulkInsertExecutor>();
342+
343+
return executor.BulkInsertValuesIntoTempTableAsync(values, tempTable, options, cancellationToken);
344+
}
345+
346+
/// <summary>
347+
/// Copies <paramref name="values"/> into a temp table and returns the query for accessing the inserted records.
348+
/// </summary>
349+
/// <param name="ctx">Database context.</param>
350+
/// <param name="values">Values to insert.</param>
351+
/// <param name="tempTable">Temp table to insert into.</param>
352+
/// <param name="options">Options.</param>
353+
/// <param name="cancellationToken">Cancellation token.</param>
354+
/// <typeparam name="TColumn1">Type of the column 1.</typeparam>
355+
/// <typeparam name="TColumn2">Type of the column 2.</typeparam>
356+
/// <returns>A query for accessing the inserted values.</returns>
357+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="values"/> is <c>null</c>.</exception>
358+
public static Task BulkInsertValuesIntoTempTableAsync<TColumn1, TColumn2>(
359+
this DbContext ctx,
360+
IEnumerable<(TColumn1 column1, TColumn2 column2)> values,
361+
ITempTableReference tempTable,
362+
ITempTableBulkInsertOptions? options,
363+
CancellationToken cancellationToken = default)
364+
{
365+
ArgumentNullException.ThrowIfNull(values);
366+
367+
var entities = values.Select(t => new TempTable<TColumn1, TColumn2>(t.column1, t.column2));
368+
369+
return ctx.BulkInsertIntoTempTableAsync(entities, tempTable, options, cancellationToken);
370+
}
371+
372+
/// <summary>
373+
/// Copies <paramref name="values"/> into a temp table and returns the query for accessing the inserted records.
374+
/// </summary>
375+
/// <param name="ctx">Database context.</param>
376+
/// <param name="values">Values to insert.</param>
377+
/// <param name="tempTable">Temp table to insert into.</param>
378+
/// <param name="options">Options.</param>
379+
/// <param name="cancellationToken">Cancellation token.</param>
380+
/// <typeparam name="TColumn1">Type of the column 1.</typeparam>
381+
/// <typeparam name="TColumn2">Type of the column 2.</typeparam>
382+
/// <returns>A query for accessing the inserted values.</returns>
383+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="values"/> is <c>null</c>.</exception>
384+
public static Task BulkInsertValuesIntoTempTableAsync<TColumn1, TColumn2>(
385+
this DbContext ctx,
386+
IEnumerable<(TColumn1 column1, TColumn2 column2)> values,
387+
ITempTableReference tempTable,
388+
IBulkInsertOptions? options = null,
389+
CancellationToken cancellationToken = default)
390+
{
391+
ArgumentNullException.ThrowIfNull(values);
392+
393+
var entities = values.Select(t => new TempTable<TColumn1, TColumn2>(t.column1, t.column2));
394+
395+
return ctx.BulkInsertIntoTempTableAsync(entities, tempTable, options, cancellationToken);
396+
}
397+
398+
/// <summary>
399+
/// Copies <paramref name="entities"/> into a temp table and returns the query for accessing the inserted records.
400+
/// </summary>
401+
/// <param name="ctx">Database context.</param>
402+
/// <param name="entities">Entities to insert.</param>
403+
/// <param name="tempTable">Temp table to insert into.</param>
404+
/// <param name="propertiesToInsert">Properties to insert. If <c>null</c> then all properties are used.</param>
405+
/// <param name="cancellationToken">Cancellation token.</param>
406+
/// <typeparam name="T">Entity type.</typeparam>
407+
/// <returns>A query for accessing the inserted values.</returns>
408+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="entities"/> is <c>null</c>.</exception>
409+
public static Task BulkInsertIntoTempTableAsync<T>(
410+
this DbContext ctx,
411+
IEnumerable<T> entities,
412+
ITempTableReference tempTable,
413+
Expression<Func<T, object?>>? propertiesToInsert = null,
414+
CancellationToken cancellationToken = default)
415+
where T : class
416+
{
417+
var executor = ctx.GetService<ITempTableBulkInsertExecutor>();
418+
var options = executor.CreateBulkInsertOptions(propertiesToInsert is null ? null : IEntityPropertiesProvider.Include(propertiesToInsert));
419+
420+
return executor.BulkInsertIntoTempTableAsync(entities, tempTable, options, cancellationToken);
421+
}
422+
423+
/// <summary>
424+
/// Copies <paramref name="entities"/> into a temp table and returns the query for accessing the inserted records.
425+
/// </summary>
426+
/// <param name="ctx">Database context.</param>
427+
/// <param name="entities">Entities to insert.</param>
428+
/// <param name="tempTable">Temp table to insert into.</param>
429+
/// <param name="options">Options.</param>
430+
/// <param name="cancellationToken">Cancellation token.</param>
431+
/// <typeparam name="T">Entity type.</typeparam>
432+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="entities"/> is <c>null</c>.</exception>
433+
public static Task BulkInsertIntoTempTableAsync<T>(
434+
this DbContext ctx,
435+
IEnumerable<T> entities,
436+
ITempTableReference tempTable,
437+
ITempTableBulkInsertOptions? options,
438+
CancellationToken cancellationToken = default)
439+
where T : class
440+
{
441+
var executor = ctx.GetService<ITempTableBulkInsertExecutor>();
442+
443+
return executor.BulkInsertIntoTempTableAsync(entities, tempTable, options, cancellationToken);
444+
}
445+
446+
/// <summary>
447+
/// Copies <paramref name="entities"/> into a temp table and returns the query for accessing the inserted records.
448+
/// </summary>
449+
/// <param name="ctx">Database context.</param>
450+
/// <param name="entities">Entities to insert.</param>
451+
/// <param name="tempTable">Temp table to insert into.</param>
452+
/// <param name="options">Options.</param>
453+
/// <param name="cancellationToken">Cancellation token.</param>
454+
/// <typeparam name="T">Entity type.</typeparam>
455+
/// <exception cref="ArgumentNullException"> <paramref name="ctx"/> or <paramref name="entities"/> is <c>null</c>.</exception>
456+
public static Task BulkInsertIntoTempTableAsync<T>(
457+
this DbContext ctx,
458+
IEnumerable<T> entities,
459+
ITempTableReference tempTable,
460+
IBulkInsertOptions? options,
461+
CancellationToken cancellationToken = default)
462+
where T : class
463+
{
464+
var executor = ctx.GetService<ITempTableBulkInsertExecutor>();
465+
466+
return executor.BulkInsertIntoTempTableAsync(entities, tempTable, options, cancellationToken);
467+
}
468+
296469
/// <summary>
297470
/// Truncates the table of the entity of type <typeparamref name="T"/>.
298471
/// </summary>

src/Thinktecture.EntityFrameworkCore.SqlServer/EntityFrameworkCore/BulkOperations/SqlServerBulkOperationExecutor.cs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ IBulkInsertOptions IBulkInsertExecutor.CreateOptions(IEntityPropertiesProvider?
5858
return new SqlServerBulkInsertOptions { PropertiesToInsert = propertiesToInsert };
5959
}
6060

61+
/// <inheritdoc />
62+
public IBulkInsertOptions CreateBulkInsertOptions(IEntityPropertiesProvider? propertiesToInsert = null)
63+
{
64+
return new SqlServerBulkInsertOptions { PropertiesToInsert = propertiesToInsert };
65+
}
66+
6167
/// <inheritdoc />
6268
ITempTableBulkInsertOptions ITempTableBulkInsertExecutor.CreateOptions(IEntityPropertiesProvider? propertiesToInsert)
6369
{
@@ -355,6 +361,100 @@ private async Task<ITempTableQuery<T>> BulkInsertIntoTempTableAsync<T, TEntity>(
355361
}
356362
}
357363

364+
/// <inheritdoc />
365+
public Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
366+
IEnumerable<TColumn1> values,
367+
ITempTableReference tempTable,
368+
ITempTableBulkInsertOptions? options,
369+
CancellationToken cancellationToken)
370+
{
371+
ArgumentNullException.ThrowIfNull(values);
372+
ArgumentNullException.ThrowIfNull(tempTable);
373+
374+
if (options is not SqlServerTempTableBulkInsertOptions sqlServerOptions)
375+
sqlServerOptions = new SqlServerTempTableBulkInsertOptions(options);
376+
377+
return BulkInsertIntoTempTableAsync<TColumn1, TempTable<TColumn1>>(values,
378+
tempTable,
379+
sqlServerOptions.GetBulkInsertOptions(),
380+
SqlServerBulkOperationContextFactoryForValues.Instance,
381+
cancellationToken);
382+
}
383+
384+
/// <inheritdoc />
385+
public Task BulkInsertValuesIntoTempTableAsync<TColumn1>(
386+
IEnumerable<TColumn1> values,
387+
ITempTableReference tempTable,
388+
IBulkInsertOptions? options,
389+
CancellationToken cancellationToken)
390+
{
391+
ArgumentNullException.ThrowIfNull(values);
392+
ArgumentNullException.ThrowIfNull(tempTable);
393+
394+
return BulkInsertIntoTempTableAsync<TColumn1, TempTable<TColumn1>>(values,
395+
tempTable,
396+
options,
397+
SqlServerBulkOperationContextFactoryForValues.Instance,
398+
cancellationToken);
399+
}
400+
401+
/// <inheritdoc />
402+
public Task BulkInsertIntoTempTableAsync<T>(
403+
IEnumerable<T> entities,
404+
ITempTableReference tempTable,
405+
ITempTableBulkInsertOptions? options,
406+
CancellationToken cancellationToken = default)
407+
where T : class
408+
{
409+
ArgumentNullException.ThrowIfNull(entities);
410+
ArgumentNullException.ThrowIfNull(tempTable);
411+
412+
if (options is not SqlServerTempTableBulkInsertOptions sqlServerOptions)
413+
sqlServerOptions = new SqlServerTempTableBulkInsertOptions(options);
414+
415+
return BulkInsertIntoTempTableAsync<T, T>(entities,
416+
tempTable,
417+
sqlServerOptions.GetBulkInsertOptions(),
418+
SqlServerBulkOperationContextFactoryForEntities.Instance,
419+
cancellationToken);
420+
}
421+
422+
/// <inheritdoc />
423+
public Task BulkInsertIntoTempTableAsync<T>(
424+
IEnumerable<T> entities,
425+
ITempTableReference tempTable,
426+
IBulkInsertOptions? options,
427+
CancellationToken cancellationToken = default)
428+
where T : class
429+
{
430+
ArgumentNullException.ThrowIfNull(entities);
431+
ArgumentNullException.ThrowIfNull(tempTable);
432+
433+
return BulkInsertIntoTempTableAsync<T, T>(entities,
434+
tempTable,
435+
options,
436+
SqlServerBulkOperationContextFactoryForEntities.Instance,
437+
cancellationToken);
438+
}
439+
440+
private async Task BulkInsertIntoTempTableAsync<T, TEntity>(
441+
IEnumerable<T> entitiesOrValues,
442+
ITempTableReference tempTable,
443+
IBulkInsertOptions? options,
444+
ISqlServerBulkOperationContextFactory bulkOperationContextFactory,
445+
CancellationToken cancellationToken)
446+
where TEntity : class
447+
{
448+
var type = typeof(TEntity);
449+
var entityTypeName = EntityNameProvider.GetTempTableName(type);
450+
var entityType = _ctx.Model.GetEntityType(entityTypeName, type);
451+
452+
if (options is not SqlServerBulkInsertOptions sqlServerOptions)
453+
sqlServerOptions = new SqlServerBulkInsertOptions(options);
454+
455+
await BulkInsertAsync(entityType, entitiesOrValues, null, tempTable.Name, sqlServerOptions, bulkOperationContextFactory, cancellationToken).ConfigureAwait(false);
456+
}
457+
358458
/// <inheritdoc />
359459
public async Task TruncateTableAsync<T>(CancellationToken cancellationToken = default)
360460
where T : class

0 commit comments

Comments
 (0)