Skip to content

Commit acfec75

Browse files
authored
Make PooledDbContextFactory public (#24712)
Closes #24137
1 parent da08e25 commit acfec75

File tree

7 files changed

+202
-193
lines changed

7 files changed

+202
-193
lines changed

src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs

Lines changed: 30 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ public static class EntityFrameworkServiceCollectionExtensions
5555
/// </param>
5656
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
5757
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
58-
/// <returns>
59-
/// The same service collection so that multiple calls can be chained.
60-
/// </returns>
58+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
6159
public static IServiceCollection AddDbContext<TContext>(
6260
this IServiceCollection serviceCollection,
6361
Action<DbContextOptionsBuilder>? optionsAction = null,
@@ -102,9 +100,7 @@ public static IServiceCollection AddDbContext<TContext>(
102100
/// </param>
103101
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
104102
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
105-
/// <returns>
106-
/// The same service collection so that multiple calls can be chained.
107-
/// </returns>
103+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
108104
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
109105
this IServiceCollection serviceCollection,
110106
Action<DbContextOptionsBuilder>? optionsAction = null,
@@ -149,16 +145,12 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
149145
/// will not be called.
150146
/// </para>
151147
/// </param>
152-
/// <param name="poolSize">
153-
/// Sets the maximum number of instances retained by the pool.
154-
/// </param>
155-
/// <returns>
156-
/// The same service collection so that multiple calls can be chained.
157-
/// </returns>
148+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
149+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
158150
public static IServiceCollection AddDbContextPool<TContext>(
159151
this IServiceCollection serviceCollection,
160152
Action<DbContextOptionsBuilder> optionsAction,
161-
int poolSize = 128)
153+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
162154
where TContext : DbContext
163155
=> AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction, poolSize);
164156

@@ -195,16 +187,12 @@ public static IServiceCollection AddDbContextPool<TContext>(
195187
/// will not be called.
196188
/// </para>
197189
/// </param>
198-
/// <param name="poolSize">
199-
/// Sets the maximum number of instances retained by the pool.
200-
/// </param>
201-
/// <returns>
202-
/// The same service collection so that multiple calls can be chained.
203-
/// </returns>
190+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
191+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
204192
public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>(
205193
this IServiceCollection serviceCollection,
206194
Action<DbContextOptionsBuilder> optionsAction,
207-
int poolSize = 128)
195+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
208196
where TContextImplementation : DbContext, TContextService
209197
where TContextService : class
210198
{
@@ -253,16 +241,12 @@ public static IServiceCollection AddDbContextPool<TContextService, TContextImple
253241
/// will not be called.
254242
/// </para>
255243
/// </param>
256-
/// <param name="poolSize">
257-
/// Sets the maximum number of instances retained by the pool.
258-
/// </param>
259-
/// <returns>
260-
/// The same service collection so that multiple calls can be chained.
261-
/// </returns>
244+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
245+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
262246
public static IServiceCollection AddDbContextPool<TContext>(
263247
this IServiceCollection serviceCollection,
264248
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
265-
int poolSize = 128)
249+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
266250
where TContext : DbContext
267251
=> AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction, poolSize);
268252

@@ -308,16 +292,12 @@ public static IServiceCollection AddDbContextPool<TContext>(
308292
/// will not be called.
309293
/// </para>
310294
/// </param>
311-
/// <param name="poolSize">
312-
/// Sets the maximum number of instances retained by the pool.
313-
/// </param>
314-
/// <returns>
315-
/// The same service collection so that multiple calls can be chained.
316-
/// </returns>
295+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
296+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
317297
public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>(
318298
this IServiceCollection serviceCollection,
319299
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
320-
int poolSize = 128)
300+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
321301
where TContextImplementation : DbContext, TContextService
322302
where TContextService : class
323303
{
@@ -381,9 +361,7 @@ private static void AddPoolingOptions<TContext>(
381361
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
382362
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
383363
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
384-
/// <returns>
385-
/// The same service collection so that multiple calls can be chained.
386-
/// </returns>
364+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
387365
public static IServiceCollection AddDbContext<TContext>(
388366
this IServiceCollection serviceCollection,
389367
ServiceLifetime contextLifetime,
@@ -411,9 +389,7 @@ public static IServiceCollection AddDbContext<TContext>(
411389
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
412390
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
413391
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
414-
/// <returns>
415-
/// The same service collection so that multiple calls can be chained.
416-
/// </returns>
392+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
417393
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
418394
this IServiceCollection serviceCollection,
419395
ServiceLifetime contextLifetime,
@@ -470,9 +446,7 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
470446
/// </param>
471447
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
472448
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
473-
/// <returns>
474-
/// The same service collection so that multiple calls can be chained.
475-
/// </returns>
449+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
476450
public static IServiceCollection AddDbContext<TContext>(
477451
this IServiceCollection serviceCollection,
478452
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
@@ -527,9 +501,7 @@ public static IServiceCollection AddDbContext<TContext>(
527501
/// </param>
528502
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
529503
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
530-
/// <returns>
531-
/// The same service collection so that multiple calls can be chained.
532-
/// </returns>
504+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
533505
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
534506
this IServiceCollection serviceCollection,
535507
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
@@ -600,9 +572,7 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
600572
/// The lifetime with which to register the factory and options.
601573
/// The default is <see cref="ServiceLifetime.Singleton" />
602574
/// </param>
603-
/// <returns>
604-
/// The same service collection so that multiple calls can be chained.
605-
/// </returns>
575+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
606576
public static IServiceCollection AddDbContextFactory<TContext>(
607577
this IServiceCollection serviceCollection,
608578
Action<DbContextOptionsBuilder>? optionsAction = null,
@@ -659,9 +629,7 @@ public static IServiceCollection AddDbContextFactory<TContext>(
659629
/// The lifetime with which to register the factory and options.
660630
/// The default is <see cref="ServiceLifetime.Singleton" />
661631
/// </param>
662-
/// <returns>
663-
/// The same service collection so that multiple calls can be chained.
664-
/// </returns>
632+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
665633
public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
666634
this IServiceCollection serviceCollection,
667635
Action<DbContextOptionsBuilder>? optionsAction = null,
@@ -727,9 +695,7 @@ public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
727695
/// The lifetime with which to register the factory and options.
728696
/// The default is <see cref="ServiceLifetime.Singleton" />
729697
/// </param>
730-
/// <returns>
731-
/// The same service collection so that multiple calls can be chained.
732-
/// </returns>
698+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
733699
public static IServiceCollection AddDbContextFactory<TContext>(
734700
this IServiceCollection serviceCollection,
735701
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
@@ -794,9 +760,7 @@ public static IServiceCollection AddDbContextFactory<TContext>(
794760
/// The lifetime with which to register the factory and options.
795761
/// The default is <see cref="ServiceLifetime.Singleton" />
796762
/// </param>
797-
/// <returns>
798-
/// The same service collection so that multiple calls can be chained.
799-
/// </returns>
763+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
800764
public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
801765
this IServiceCollection serviceCollection,
802766
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
@@ -850,16 +814,12 @@ public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
850814
/// will not be called.
851815
/// </para>
852816
/// </param>
853-
/// <param name="poolSize">
854-
/// Sets the maximum number of instances retained by the pool.
855-
/// </param>
856-
/// <returns>
857-
/// The same service collection so that multiple calls can be chained.
858-
/// </returns>
817+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
818+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
859819
public static IServiceCollection AddPooledDbContextFactory<TContext>(
860820
this IServiceCollection serviceCollection,
861821
Action<DbContextOptionsBuilder> optionsAction,
862-
int poolSize = 128)
822+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
863823
where TContext : DbContext
864824
{
865825
Check.NotNull(optionsAction, nameof(optionsAction));
@@ -898,16 +858,12 @@ public static IServiceCollection AddPooledDbContextFactory<TContext>(
898858
/// will not be called.
899859
/// </para>
900860
/// </param>
901-
/// <param name="poolSize">
902-
/// Sets the maximum number of instances retained by the pool.
903-
/// </param>
904-
/// <returns>
905-
/// The same service collection so that multiple calls can be chained.
906-
/// </returns>
861+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
862+
/// <returns> The same service collection so that multiple calls can be chained. </returns>
907863
public static IServiceCollection AddPooledDbContextFactory<TContext>(
908864
this IServiceCollection serviceCollection,
909865
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
910-
int poolSize = 128)
866+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
911867
where TContext : DbContext
912868
{
913869
Check.NotNull(serviceCollection, nameof(serviceCollection));
@@ -916,7 +872,8 @@ public static IServiceCollection AddPooledDbContextFactory<TContext>(
916872
AddPoolingOptions<TContext>(serviceCollection, optionsAction, poolSize);
917873

918874
serviceCollection.TryAddSingleton<IDbContextPool<TContext>, DbContextPool<TContext>>();
919-
serviceCollection.TryAddSingleton<IDbContextFactory<TContext>, PooledDbContextFactory<TContext>>();
875+
serviceCollection.TryAddSingleton<IDbContextFactory<TContext>>(
876+
sp => new PooledDbContextFactory<TContext>(sp.GetRequiredService<IDbContextPool<TContext>>()));
920877

921878
return serviceCollection;
922879
}

src/EFCore/IDbContextFactory.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ namespace Microsoft.EntityFrameworkCore
55
{
66
/// <summary>
77
/// Defines a factory for creating <see cref="DbContext" /> instances.
8-
/// A service of this type is registered in the dependency injection container by the
9-
/// <see cref="M:EntityFrameworkServiceCollectionExtensions.AddDbContextPool" /> methods.
108
/// </summary>
119
/// <typeparam name="TContext"> The <see cref="DbContext" /> type to create. </typeparam>
1210
public interface IDbContextFactory<out TContext>
@@ -17,7 +15,7 @@ public interface IDbContextFactory<out TContext>
1715
/// Creates a new <see cref="DbContext" /> instance.
1816
/// </para>
1917
/// <para>
20-
/// The caller is responsible for disposing the context; it will not be disposed by the dependency injection container.
18+
/// The caller is responsible for disposing the context; it will not be disposed by any dependency injection container.
2119
/// </para>
2220
/// </summary>
2321
/// <returns> A new context instance. </returns>

src/EFCore/Infrastructure/CoreOptionsExtension.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,11 @@ public virtual void ApplyServices(IServiceCollection services)
488488
/// <param name="options"> The options being validated. </param>
489489
public virtual void Validate(IDbContextOptions options)
490490
{
491+
if (MaxPoolSize.HasValue && MaxPoolSize <= 0)
492+
{
493+
throw new ArgumentOutOfRangeException(nameof(MaxPoolSize), CoreStrings.InvalidPoolSize);
494+
}
495+
491496
if (_internalServiceProvider != null)
492497
{
493498
if (ReplacedServices != null)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.EntityFrameworkCore.Internal;
5+
6+
namespace Microsoft.EntityFrameworkCore.Infrastructure
7+
{
8+
/// <summary>
9+
/// <para>
10+
/// A factory returning pooled <see cref="DbContext" /> instances. Disposing the instance returned by this factory returns
11+
/// them to the internal pooling mechanism.
12+
/// </para>
13+
/// <para>
14+
/// A service of this type is registered in the dependency injection container by the
15+
/// <see cref="M:EntityFrameworkServiceCollectionExtensions.AddDbContextPool" /> methods.
16+
/// </para>
17+
/// </summary>
18+
public class PooledDbContextFactory<TContext> : IDbContextFactory<TContext>
19+
where TContext : DbContext
20+
{
21+
private readonly IDbContextPool<TContext> _pool;
22+
23+
/// <summary>
24+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
25+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
26+
/// any release. You should only use it directly in your code with extreme caution and knowing that
27+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
28+
/// </summary>
29+
[EntityFrameworkInternal]
30+
public PooledDbContextFactory(IDbContextPool<TContext> pool)
31+
=> _pool = pool;
32+
33+
/// <summary>
34+
/// Initializes a new instance of the <see cref="PooledDbContextFactory{TContext}" /> class.
35+
/// </summary>
36+
/// <param name="options"> The options to use for contexts produced by this factory. </param>
37+
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
38+
public PooledDbContextFactory(DbContextOptions<TContext> options, int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
39+
{
40+
var optionsBuilder = new DbContextOptionsBuilder<TContext>(options);
41+
42+
var extension = (options.FindExtension<CoreOptionsExtension>() ?? new CoreOptionsExtension())
43+
.WithMaxPoolSize(poolSize);
44+
45+
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
46+
47+
_pool = new DbContextPool<TContext>(optionsBuilder.Options);
48+
}
49+
50+
/// <inheritdoc />
51+
public virtual TContext CreateDbContext()
52+
=> (TContext)new DbContextLease(_pool, standalone: true).Context;
53+
}
54+
}

0 commit comments

Comments
 (0)