Skip to content

Commit 53070f8

Browse files
committed
Add DbContextOptions composibility support
1 parent 32c6133 commit 53070f8

File tree

17 files changed

+556
-293
lines changed

17 files changed

+556
-293
lines changed

benchmark/EFCore.Benchmarks/Initialization/InitializationTests.cs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,77 @@
66
using BenchmarkDotNet.Attributes;
77
using Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
88
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
9+
using Microsoft.Extensions.DependencyInjection;
910

1011
namespace Microsoft.EntityFrameworkCore.Benchmarks.Initialization;
1112

1213
[DisplayName("InitializationTests")]
1314
public abstract class InitializationTests
1415
{
16+
private ServiceProvider _serviceProvider;
17+
private ServiceProvider _pooledServiceProvider;
18+
1519
protected abstract AdventureWorksContextBase CreateContext();
1620
protected abstract ConventionSet CreateConventionSet();
21+
protected abstract IServiceCollection AddContext(IServiceCollection services);
22+
protected abstract IServiceCollection AddContextPool(IServiceCollection services);
23+
24+
[GlobalSetup]
25+
public virtual void Initialize()
26+
{
27+
_serviceProvider = AddContext(new ServiceCollection()).BuildServiceProvider();
28+
_pooledServiceProvider = AddContextPool(new ServiceCollection()).BuildServiceProvider();
29+
}
1730

1831
[Benchmark]
1932
public virtual void CreateAndDisposeUnusedContext()
2033
{
2134
for (var i = 0; i < 10000; i++)
2235
{
2336
// ReSharper disable once UnusedVariable
24-
using (var context = CreateContext())
25-
{
26-
}
37+
using var context = CreateContext();
38+
}
39+
}
40+
41+
[Benchmark]
42+
public virtual void CreateAndDisposeUnusedContextFromDi()
43+
{
44+
for (var i = 0; i < 10000; i++)
45+
{
46+
using var scope = _serviceProvider.CreateScope();
47+
var context = scope.ServiceProvider.GetService<AdventureWorksContextBase>();
48+
}
49+
}
50+
51+
[Benchmark]
52+
public virtual void CreateAndDisposeUnusedContextFromDiFactory()
53+
{
54+
var factory = _serviceProvider.GetService<IDbContextFactory<AdventureWorksContextBase>>();
55+
for (var i = 0; i < 10000; i++)
56+
{
57+
using var _ = factory.CreateDbContext();
58+
}
59+
}
60+
61+
[Benchmark]
62+
public virtual void CreateAndDisposePooledContextFromDi()
63+
{
64+
for (var i = 0; i < 10000; i++)
65+
{
66+
using var scope = _pooledServiceProvider.CreateScope();
67+
var context = (AdventureWorksContextBase)scope.ServiceProvider.GetService(typeof(AdventureWorksContextBase));
68+
var _ = context.Model;
69+
}
70+
}
71+
72+
[Benchmark]
73+
public virtual void CreateAndDisposePooledContextFromDiFactory()
74+
{
75+
var factory = _pooledServiceProvider.GetService<IDbContextFactory<AdventureWorksContextBase>>();
76+
for (var i = 0; i < 10000; i++)
77+
{
78+
using var context = factory.CreateDbContext();
79+
var _ = context.Model;
2780
}
2881
}
2982

benchmark/EFCore.Benchmarks/Models/AdventureWorks/AdventureWorksContextBase.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55

66
public abstract class AdventureWorksContextBase : DbContext
77
{
8+
public AdventureWorksContextBase()
9+
{
10+
}
11+
12+
public AdventureWorksContextBase(DbContextOptions options)
13+
: base(options)
14+
{
15+
}
16+
817
public virtual DbSet<Address> Address { get; set; }
918
public virtual DbSet<AddressType> AddressType { get; set; }
1019
public virtual DbSet<BillOfMaterials> BillOfMaterials { get; set; }

benchmark/EFCore.SqlServer.Benchmarks/Initialization/InitializationSqlServerTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.DependencyInjection.Extensions;
68

79
namespace Microsoft.EntityFrameworkCore.Benchmarks.Initialization;
810

@@ -13,4 +15,37 @@ protected override AdventureWorksContextBase CreateContext()
1315

1416
protected override ConventionSet CreateConventionSet()
1517
=> SqlServerConventionSetBuilder.Build();
18+
19+
protected override IServiceCollection AddContext(IServiceCollection services)
20+
{
21+
services.AddDbContext<AdventureWorksContextBase, AdventureWorksSqlServerContext>()
22+
.AddDbContextFactory<AdventureWorksSqlServerContext>()
23+
.TryAddSingleton<IDbContextFactory<AdventureWorksContextBase>,
24+
AdventureWorksSqlServerContextFactory<AdventureWorksSqlServerContext>>();
25+
26+
return services;
27+
}
28+
29+
protected override IServiceCollection AddContextPool(IServiceCollection services)
30+
{
31+
services.AddDbContextPool<AdventureWorksContextBase, AdventureWorksPoolableSqlServerContext>(
32+
AdventureWorksSqlServerFixture.ConfigureOptions)
33+
.AddPooledDbContextFactory<AdventureWorksPoolableSqlServerContext>(AdventureWorksSqlServerFixture.ConfigureOptions)
34+
.TryAddSingleton<IDbContextFactory<AdventureWorksContextBase>,
35+
AdventureWorksSqlServerContextFactory<AdventureWorksPoolableSqlServerContext>>();
36+
37+
return services;
38+
}
39+
40+
private class AdventureWorksSqlServerContextFactory<T> : IDbContextFactory<AdventureWorksContextBase>
41+
where T : AdventureWorksContextBase
42+
{
43+
private readonly IDbContextFactory<T> _factory;
44+
45+
public AdventureWorksSqlServerContextFactory(IDbContextFactory<T> factory)
46+
=> _factory = factory;
47+
48+
public AdventureWorksContextBase CreateDbContext()
49+
=> _factory.CreateDbContext();
50+
}
1651
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
5+
6+
public class AdventureWorksPoolableSqlServerContext : AdventureWorksContextBase
7+
{
8+
public AdventureWorksPoolableSqlServerContext(DbContextOptions<AdventureWorksPoolableSqlServerContext> options)
9+
: base(options)
10+
{
11+
}
12+
13+
protected override void ConfigureProvider(DbContextOptionsBuilder optionsBuilder)
14+
{
15+
}
16+
}

benchmark/EFCore.SqlServer.Benchmarks/Models/AdventureWorks/AdventureWorksSqlServerContext.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55

66
public class AdventureWorksSqlServerContext : AdventureWorksContextBase
77
{
8-
private readonly string _connectionString;
9-
10-
public AdventureWorksSqlServerContext(string connectionString)
11-
{
12-
_connectionString = connectionString;
13-
}
14-
158
protected override void ConfigureProvider(DbContextOptionsBuilder optionsBuilder)
16-
=> optionsBuilder.UseSqlServer(_connectionString);
9+
=> optionsBuilder.UseSqlServer(AdventureWorksSqlServerFixture.ConnectionString);
1710
}

benchmark/EFCore.SqlServer.Benchmarks/Models/AdventureWorks/AdventureWorksSqlServerFixture.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55

66
public static class AdventureWorksSqlServerFixture
77
{
8-
private static readonly string _connectionString = SqlServerBenchmarkEnvironment.CreateConnectionString("AdventureWorks2014");
8+
public static string ConnectionString { get; } = SqlServerBenchmarkEnvironment.CreateConnectionString("AdventureWorks2014");
99

1010
// This method is called from timed code, be careful when changing it
1111
public static AdventureWorksContextBase CreateContext()
12-
=> new AdventureWorksSqlServerContext(_connectionString);
12+
=> new AdventureWorksSqlServerContext();
13+
14+
public static void ConfigureOptions(DbContextOptionsBuilder optionsBuilder)
15+
=> optionsBuilder.UseSqlServer(ConnectionString);
1316
}

benchmark/EFCore.Sqlite.Benchmarks/Initialization/InitializationSqliteTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.DependencyInjection.Extensions;
68

79
namespace Microsoft.EntityFrameworkCore.Benchmarks.Initialization;
810

@@ -13,4 +15,37 @@ protected override AdventureWorksContextBase CreateContext()
1315

1416
protected override ConventionSet CreateConventionSet()
1517
=> SqliteConventionSetBuilder.Build();
18+
19+
protected override IServiceCollection AddContext(IServiceCollection services)
20+
{
21+
services.AddDbContext<AdventureWorksContextBase, AdventureWorksSqliteContext>()
22+
.AddDbContextFactory<AdventureWorksSqliteContext>()
23+
.TryAddSingleton<IDbContextFactory<AdventureWorksContextBase>,
24+
AdventureWorksSqliteContextFactory<AdventureWorksSqliteContext>>();
25+
26+
return services;
27+
}
28+
29+
protected override IServiceCollection AddContextPool(IServiceCollection services)
30+
{
31+
services.AddDbContextPool<AdventureWorksContextBase, AdventureWorksPoolableSqliteContext>(
32+
AdventureWorksSqliteFixture.ConfigureOptions)
33+
.AddPooledDbContextFactory<AdventureWorksPoolableSqliteContext>(AdventureWorksSqliteFixture.ConfigureOptions)
34+
.TryAddSingleton<IDbContextFactory<AdventureWorksContextBase>,
35+
AdventureWorksSqliteContextFactory<AdventureWorksPoolableSqliteContext>>();
36+
37+
return services;
38+
}
39+
40+
private class AdventureWorksSqliteContextFactory<T> : IDbContextFactory<AdventureWorksContextBase>
41+
where T : AdventureWorksContextBase
42+
{
43+
private readonly IDbContextFactory<T> _factory;
44+
45+
public AdventureWorksSqliteContextFactory(IDbContextFactory<T> factory)
46+
=> _factory = factory;
47+
48+
public AdventureWorksContextBase CreateDbContext()
49+
=> _factory.CreateDbContext();
50+
}
1651
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
5+
6+
public class AdventureWorksPoolableSqliteContext : AdventureWorksContextBase
7+
{
8+
public AdventureWorksPoolableSqliteContext(DbContextOptions<AdventureWorksPoolableSqliteContext> options)
9+
: base(options)
10+
{
11+
}
12+
13+
protected override void ConfigureProvider(DbContextOptionsBuilder optionsBuilder)
14+
{
15+
}
16+
}

benchmark/EFCore.Sqlite.Benchmarks/Models/AdventureWorks/AdventureWorksSqliteContext.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ namespace Microsoft.EntityFrameworkCore.Benchmarks.Models.AdventureWorks;
55

66
public class AdventureWorksSqliteContext : AdventureWorksContextBase
77
{
8-
private readonly string _connectionString;
9-
10-
public AdventureWorksSqliteContext(string connectionString)
11-
{
12-
_connectionString = connectionString;
13-
}
14-
158
protected override void ConfigureProvider(DbContextOptionsBuilder optionsBuilder)
16-
=> optionsBuilder.UseSqlite(_connectionString);
9+
=> optionsBuilder.UseSqlite(AdventureWorksSqliteFixture.ConnectionString);
1710
}

benchmark/EFCore.Sqlite.Benchmarks/Models/AdventureWorks/AdventureWorksSqliteFixture.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ public static class AdventureWorksSqliteFixture
1010
private static readonly string _baseDirectory
1111
= Path.GetDirectoryName(typeof(AdventureWorksSqliteFixture).Assembly.Location);
1212

13-
private static readonly string _connectionString
14-
= $"Data Source={Path.Combine(_baseDirectory, "AdventureWorks2014.db")}";
13+
public static string ConnectionString { get; } = $"Data Source={Path.Combine(_baseDirectory, "AdventureWorks2014.db")}";
1514

1615
// This method is called from timed code, be careful when changing it
1716
public static AdventureWorksContextBase CreateContext()
18-
=> new AdventureWorksSqliteContext(_connectionString);
17+
=> new AdventureWorksSqliteContext();
18+
19+
public static void ConfigureOptions(DbContextOptionsBuilder optionsBuilder)
20+
=> optionsBuilder.UseSqlite(ConnectionString);
1921
}

0 commit comments

Comments
 (0)