Skip to content

Commit 8132028

Browse files
authored
Add parameterless overload for AddPooledDbContextFactory<TContext> aligning pooled factory with ConfigureDbContext<TContext>. (#37144)
Fixes #34657
1 parent 2f5c7f3 commit 8132028

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,61 @@ public static IServiceCollection AddPooledDbContextFactory
10281028
return serviceCollection;
10291029
}
10301030

1031+
/// <summary>
1032+
/// Registers a pooled <see cref="IDbContextFactory{TContext}" /> in the
1033+
/// <see cref="IServiceCollection" /> for creating instances of the specified
1034+
/// <see cref="DbContext" /> type, using a custom pool size.
1035+
/// </summary>
1036+
/// <remarks>
1037+
/// <para>
1038+
/// This overload aligns with the EF Core centralized configuration model
1039+
/// <see cref="ConfigureDbContext{TContext}(IServiceCollection, Action{DbContextOptionsBuilder}, ServiceLifetime)" />.
1040+
/// and allows specifying a custom <paramref name="poolSize"/>.
1041+
/// Options configured via <c>ConfigureDbContext&lt;TContext&gt;</c> are automatically used,
1042+
/// eliminating the need to repeat provider configuration.
1043+
/// </para>
1044+
/// <para>
1045+
/// Use this method when using dependency injection in your application, such as with ASP.NET Core.
1046+
/// For applications that don't use dependency injection, consider creating <see cref="DbContext" />
1047+
/// instances directly with its constructor. The <see cref="DbContext.OnConfiguring" /> method can then be
1048+
/// overridden to configure a connection string and other options.
1049+
/// </para>
1050+
/// <para>
1051+
/// Entity Framework Core does not support multiple parallel operations being run on the same <see cref="DbContext" />
1052+
/// instance. This includes both parallel execution of async queries and any explicit concurrent use from multiple threads.
1053+
/// Therefore, always await async calls immediately, or use separate DbContext instances for operations that execute
1054+
/// in parallel. See <see href="https://aka.ms/efcore-docs-threading">Avoiding DbContext threading issues</see> for more information
1055+
/// and examples.
1056+
/// </para>
1057+
/// <para>
1058+
/// See <see href="https://aka.ms/efcore-docs-di">Using DbContext with dependency injection</see>,
1059+
/// <see href="https://aka.ms/efcore-docs-dbcontext-factory">Using DbContext factories</see>, and
1060+
/// <see href="https://aka.ms/efcore-docs-dbcontext-pooling">Using DbContext pooling</see>
1061+
/// for more information and examples.
1062+
/// </para>
1063+
/// </remarks>
1064+
/// <typeparam name="TContext">
1065+
/// The type of <see cref="DbContext" /> to be created by the factory.
1066+
/// </typeparam>
1067+
/// <param name="serviceCollection">
1068+
/// The <see cref="IServiceCollection" /> to which the services are added.
1069+
/// </param>
1070+
/// <param name="poolSize">
1071+
/// The maximum number of <typeparamref name="TContext" /> instances retained by the pool. Defaults to 1024.
1072+
/// </param>
1073+
/// <returns>
1074+
/// The same <see cref="IServiceCollection" /> so that multiple calls can be chained.
1075+
/// </returns>
1076+
public static IServiceCollection AddPooledDbContextFactory
1077+
<[DynamicallyAccessedMembers(DbContext.DynamicallyAccessedMemberTypes)] TContext>(
1078+
this IServiceCollection serviceCollection,
1079+
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
1080+
where TContext : DbContext
1081+
=> AddPooledDbContextFactory<TContext>(
1082+
serviceCollection,
1083+
static (_, __) => { },
1084+
poolSize);
1085+
10311086
/// <summary>
10321087
/// Configures the given context type in the <see cref="IServiceCollection" />.
10331088
/// </summary>

test/EFCore.SqlServer.FunctionalTests/DbContextPoolingTest.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,43 @@ public void Options_modified_in_on_configuring_with_factory()
392392
}
393393
}
394394

395+
[Fact]
396+
public async Task Parameterless_pooled_factory_should_use_ConfigureDbContext_options()
397+
{
398+
var services = new ServiceCollection();
399+
400+
services.ConfigureDbContext<DefaultOptionsPooledContext>(ob => ob.UseSqlServer(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString)
401+
.EnableServiceProviderCaching(false));
402+
403+
services.AddPooledDbContextFactory<DefaultOptionsPooledContext>();
404+
405+
using var provider = services.BuildServiceProvider();
406+
var factory = provider.GetRequiredService<IDbContextFactory<DefaultOptionsPooledContext>>();
407+
await using var db = await factory.CreateDbContextAsync();
408+
409+
Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", db.Database.ProviderName);
410+
}
411+
412+
[Fact]
413+
public async Task Parameterless_pooled_factory_with_custom_pool_size_should_still_resolve()
414+
{
415+
var services = new ServiceCollection();
416+
417+
services.ConfigureDbContext<DefaultOptionsPooledContext>(ob => ob.UseSqlServer(SqlServerNorthwindTestStoreFactory.NorthwindConnectionString)
418+
.EnableServiceProviderCaching(false));
419+
420+
services.AddPooledDbContextFactory<DefaultOptionsPooledContext>(poolSize: 256);
421+
422+
using var provider = services.BuildServiceProvider();
423+
var factory = provider.GetRequiredService<IDbContextFactory<DefaultOptionsPooledContext>>();
424+
await using var db = await factory.CreateDbContextAsync();
425+
426+
Assert.Equal("Microsoft.EntityFrameworkCore.SqlServer", db.Database.ProviderName);
427+
Assert.Equal(
428+
256,
429+
db.GetService<IDbContextOptions>().FindExtension<CoreOptionsExtension>()!.MaxPoolSize);
430+
}
431+
395432
private class BadCtorContext : DbContext;
396433

397434
[ConditionalFact]
@@ -1447,6 +1484,7 @@ public async Task Double_dispose_with_standalone_lease_does_not_enter_pool_twice
14471484
: BuildServiceProvider<PooledContext>();
14481485

14491486
var pool = serviceProvider.GetRequiredService<IDbContextPool<PooledContext>>();
1487+
Assert.Same(pool, serviceProvider.GetRequiredService<IDbContextPool<PooledContext>>());
14501488
var lease = new DbContextLease(pool, standalone: true);
14511489
var context = (PooledContext)lease.Context;
14521490
((IDbContextPoolable)context).SetLease(lease);

0 commit comments

Comments
 (0)