Skip to content

Commit 5f71620

Browse files
committed
TempTables for primitive types are pre-configured by a convention.
1 parent d7ca47a commit 5f71620

File tree

13 files changed

+201
-7
lines changed

13 files changed

+201
-7
lines changed

samples/Thinktecture.EntityFrameworkCore.Benchmarks/BenchmarkContext.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Configuration;
22
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Logging.Abstractions;
34
using Thinktecture.Database;
45

56
namespace Thinktecture;
@@ -14,11 +15,18 @@ public BenchmarkContext()
1415

1516
var services = new ServiceCollection()
1617
.AddDbContext<SqliteBenchmarkDbContext>(builder => builder.UseSqlite(config.GetConnectionString("sqlite"),
17-
optionsBuilder => optionsBuilder.AddBulkOperationSupport()))
18+
optionsBuilder => optionsBuilder
19+
.AddBulkOperationSupport())
20+
.UseLoggerFactory(NullLoggerFactory.Instance)
21+
)
1822
.AddDbContext<SqlServerBenchmarkDbContext>(builder => builder.UseSqlServer(config.GetConnectionString("sqlServer"),
19-
optionsBuilder => optionsBuilder.AddBulkOperationSupport()));
23+
optionsBuilder => optionsBuilder
24+
.AddBulkOperationSupport()
25+
.AddCollectionParameterSupport())
26+
.UseLoggerFactory(NullLoggerFactory.Instance)
27+
);
2028

21-
RootServiceProvider = services.BuildServiceProvider();
29+
RootServiceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true, ValidateOnBuild = true });
2230
}
2331

2432
private static IConfiguration GetConfiguration()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using BenchmarkDotNet.Attributes;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Thinktecture.Database;
4+
using Thinktecture.EntityFrameworkCore.BulkOperations;
5+
6+
namespace Thinktecture.Benchmarking;
7+
8+
[MemoryDiagnoser]
9+
public class ComplexCollectionParameter : IDisposable
10+
{
11+
private BenchmarkContext? _benchmarkContext;
12+
private IServiceScope? _scope;
13+
private SqlServerBenchmarkDbContext? _sqlServerDbContext;
14+
private readonly SqlServerTempTableBulkInsertOptions _sqlServerOptions = new();
15+
16+
private readonly MyParameter[] _objects = Enumerable.Range(1, 500).Select(i => new MyParameter(Guid.NewGuid(), i.ToString())).ToArray();
17+
18+
[GlobalSetup]
19+
public void Initialize()
20+
{
21+
_benchmarkContext = new BenchmarkContext();
22+
_scope = _benchmarkContext.RootServiceProvider.CreateScope();
23+
_sqlServerDbContext = _scope.ServiceProvider.GetRequiredService<SqlServerBenchmarkDbContext>();
24+
25+
_sqlServerDbContext.CreateComplexCollectionParameter(_objects).Count();
26+
TempTable().Wait();
27+
}
28+
29+
[GlobalCleanup]
30+
public void Dispose()
31+
{
32+
_scope?.Dispose();
33+
_benchmarkContext?.Dispose();
34+
}
35+
36+
[Benchmark]
37+
public int Json()
38+
{
39+
return _sqlServerDbContext!.CreateComplexCollectionParameter(_objects).Count();
40+
}
41+
42+
[Benchmark]
43+
public async Task<int> TempTable()
44+
{
45+
await using var tempTable = await _sqlServerDbContext!.BulkInsertIntoTempTableAsync(_objects, _sqlServerOptions);
46+
47+
return tempTable.Query.Count();
48+
}
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using BenchmarkDotNet.Attributes;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Thinktecture.Database;
4+
using Thinktecture.EntityFrameworkCore.BulkOperations;
5+
6+
namespace Thinktecture.Benchmarking;
7+
8+
[MemoryDiagnoser]
9+
public class ScalarCollectionParameter : IDisposable
10+
{
11+
private BenchmarkContext? _benchmarkContext;
12+
private IServiceScope? _scope;
13+
private SqlServerBenchmarkDbContext? _sqlServerDbContext;
14+
private readonly SqlServerTempTableBulkInsertOptions _sqlServerOptions = new();
15+
16+
private readonly Guid[] _values = Enumerable.Range(1, 500).Select(i => Guid.NewGuid()).ToArray();
17+
18+
[GlobalSetup]
19+
public void Initialize()
20+
{
21+
_benchmarkContext = new BenchmarkContext();
22+
_scope = _benchmarkContext.RootServiceProvider.CreateScope();
23+
_sqlServerDbContext = _scope.ServiceProvider.GetRequiredService<SqlServerBenchmarkDbContext>();
24+
25+
_sqlServerDbContext.CreateScalarCollectionParameter(_values).Count();
26+
TempTable().Wait();
27+
}
28+
29+
[GlobalCleanup]
30+
public void Dispose()
31+
{
32+
_scope?.Dispose();
33+
_benchmarkContext?.Dispose();
34+
}
35+
36+
[Benchmark]
37+
public int Json()
38+
{
39+
return _sqlServerDbContext!.CreateScalarCollectionParameter(_values).Count();
40+
}
41+
42+
[Benchmark]
43+
public async Task<int> TempTable()
44+
{
45+
await using var tempTable = await _sqlServerDbContext!.BulkInsertValuesIntoTempTableAsync(_values, _sqlServerOptions);
46+
47+
return tempTable.Query.Count();
48+
}
49+
}

samples/Thinktecture.EntityFrameworkCore.Benchmarks/Database/BenchmarkDbContext.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ protected BenchmarkDbContext(DbContextOptions options)
1111

1212
protected override void OnModelCreating(ModelBuilder modelBuilder)
1313
{
14-
modelBuilder.ConfigureTempTable<int>();
1514
modelBuilder.ConfigureTempTable<int, int>();
1615
}
1716
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace Thinktecture.Database;
2+
3+
public record MyParameter(Guid Column1, string Column2);

samples/Thinktecture.EntityFrameworkCore.Benchmarks/Database/SqlServerBenchmarkDbContext.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,16 @@ public SqlServerBenchmarkDbContext(DbContextOptions<SqlServerBenchmarkDbContext>
66
: base(options)
77
{
88
}
9+
10+
/// <inheritdoc />
11+
protected override void OnModelCreating(ModelBuilder modelBuilder)
12+
{
13+
base.OnModelCreating(modelBuilder);
14+
15+
modelBuilder.ConfigureScalarCollectionParameter<decimal>(builder => builder.Property(e => e.Value).HasPrecision(10, 4));
16+
17+
modelBuilder.ConfigureComplexCollectionParameter<MyParameter>();
18+
19+
modelBuilder.ConfigureTempTableEntity<MyParameter>();
20+
}
921
}

samples/Thinktecture.EntityFrameworkCore.Benchmarks/Program.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
using Thinktecture.Benchmarking;
33

44
// BenchmarkRunner.Run<CreateTempTable>();
5-
BenchmarkRunner.Run<BulkInsertIntoTempTable>();
5+
// BenchmarkRunner.Run<BulkInsertIntoTempTable>();
6+
// BenchmarkRunner.Run<ScalarCollectionParameter>();
7+
BenchmarkRunner.Run<ComplexCollectionParameter>();
68

79
// await ExecuteCreateTableAsync();
810
// await ExecuteBulkInsertIntoTempTableAsync();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
3+
4+
namespace Thinktecture.EntityFrameworkCore.BulkOperations;
5+
6+
/// <summary>
7+
/// Conventions for bulk operations.
8+
/// </summary>
9+
public class BulkOperationConventionSetPlugin : IConventionSetPlugin
10+
{
11+
/// <inheritdoc />
12+
public ConventionSet ModifyConventions(ConventionSet conventionSet)
13+
{
14+
conventionSet.ModelInitializedConventions.Add(TempTableConvention.Instance);
15+
16+
return conventionSet;
17+
}
18+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Microsoft.EntityFrameworkCore.Infrastructure;
2+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
3+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
4+
using Thinktecture.EntityFrameworkCore.TempTables;
5+
using Thinktecture.Internal;
6+
7+
namespace Thinktecture.EntityFrameworkCore.BulkOperations;
8+
9+
/// <summary>
10+
/// Configures some temp tables for primitive types.
11+
/// </summary>
12+
public class TempTableConvention : IModelInitializedConvention
13+
{
14+
/// <summary>
15+
/// Singleton.
16+
/// </summary>
17+
public static readonly IModelInitializedConvention Instance = new TempTableConvention();
18+
19+
/// <inheritdoc />
20+
public void ProcessModelInitialized(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
21+
{
22+
AddTempTable<int>(modelBuilder);
23+
AddTempTable<long>(modelBuilder);
24+
AddTempTable<DateTime>(modelBuilder);
25+
AddTempTable<Guid>(modelBuilder);
26+
AddTempTable<bool>(modelBuilder);
27+
AddTempTable<byte>(modelBuilder);
28+
AddTempTable<double>(modelBuilder);
29+
AddTempTable<DateTimeOffset>(modelBuilder);
30+
AddTempTable<short>(modelBuilder);
31+
AddTempTable<float>(modelBuilder);
32+
AddTempTable<decimal>(modelBuilder);
33+
AddTempTable<TimeSpan>(modelBuilder);
34+
AddTempTable<string>(modelBuilder);
35+
}
36+
37+
private static void AddTempTable<TColumn1>(IConventionModelBuilder modelBuilder)
38+
{
39+
var type = typeof(TempTable<TColumn1>);
40+
var builder = modelBuilder.SharedTypeEntity(EntityNameProvider.GetTempTableName(type), type, fromDataAnnotation: true);
41+
42+
if (builder is null)
43+
return;
44+
45+
builder.ToTable($"#{type.ShortDisplayName()}");
46+
builder.HasNoKey();
47+
builder.ExcludeTableFromMigrations(true);
48+
}
49+
}

src/Thinktecture.EntityFrameworkCore.SqlServer/EntityFrameworkCore/Infrastructure/SqlServerDbContextOptionsExtension.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ public void ApplyServices(IServiceCollection services)
127127

128128
if (AddBulkOperationSupport)
129129
{
130+
services.Add<IConventionSetPlugin, BulkOperationConventionSetPlugin>(GetLifetime<IConventionSetPlugin>());
131+
130132
services.AddSingleton<TempTableStatementCache<SqlServerTempTableCreatorCacheKey>>();
131133
services.AddSingleton<TempTableStatementCache<SqlServerTempTablePrimaryKeyCacheKey>>();
132134
services.TryAddScoped<ISqlServerTempTableCreator, SqlServerTempTableCreator>();

0 commit comments

Comments
 (0)