-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Add parameterless overloads for AddPooledDbContextFactory<TContext> #37144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1028,6 +1028,83 @@ public static IServiceCollection AddPooledDbContextFactory | |||||||||||||||||||||||||||||||||||||||||||||||||
| return serviceCollection; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Registers a pooled <see cref="IDbContextFactory{TContext}" /> in the | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <see cref="IServiceCollection" /> for creating instances of the specified | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <see cref="DbContext" /> type. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <remarks> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <para> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// This parameterless overload aligns the pooled factory with the centralized | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// configuration model introduced by | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <see cref="ConfigureDbContext{TContext}(IServiceCollection, Action{DbContextOptionsBuilder}, ServiceLifetime)"/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// When used together, options (including the database provider) configured in | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <c>ConfigureDbContext<TContext></c> automatically flow into the pooled factory, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// avoiding redundant configuration lambdas. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </para> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <para> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// See <see href="https://aka.ms/efcore-docs-di">Using DbContext with dependency injection</see>, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <see href="https://aka.ms/efcore-docs-dbcontext-factory">Using DbContext factories</see>, and | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <see href="https://aka.ms/efcore-docs-dbcontext-pooling">Using DbContext pooling</see> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// for more information and examples. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </para> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </para> | |
| /// </para> | |
| /// <para> | |
| /// <b>Pooling behavior:</b> When pooling is enabled, <see cref="DbContext" /> instances are reused to improve performance. | |
| /// Pooled contexts must not be shared between threads or requests, and should be disposed as soon as possible after use. | |
| /// Do not cache or store pooled <see cref="DbContext" /> instances for later use. For more information, see | |
| /// <see href="https://aka.ms/efcore-docs-dbcontext-pooling">Using DbContext pooling</see>. | |
| /// </para> |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace present at the end of the line. According to the coding guidelines, trailing whitespace should be removed.
| /// and allows specifying a custom <paramref name="poolSize"/>. | |
| /// and allows specifying a custom <paramref name="poolSize"/>. |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <remarks> section should include additional standard documentation paragraphs similar to existing overloads. Looking at lines 977-1001, the existing overloads document: 1) When to use factory vs direct registration (Blazor scenarios), 2) DI vs. non-DI usage, and 3) Threading constraints. These are important for API consistency and completeness.
| /// </para> | |
| /// </para> | |
| /// <para> | |
| /// Use <see cref="AddPooledDbContextFactory{TContext}(IServiceCollection, int)" /> when you need to create | |
| /// <see cref="DbContext" /> instances in scenarios where dependency injection cannot be used, such as in Blazor | |
| /// applications or background services. For typical ASP.NET Core applications where a single context instance is | |
| /// used per request, consider using <see cref="AddDbContext{TContext}(IServiceCollection, Action{DbContextOptionsBuilder}?, ServiceLifetime, ServiceLifetime)" /> | |
| /// instead. | |
| /// </para> | |
| /// <para> | |
| /// For applications that don't use dependency injection, consider creating <see cref="DbContext" /> instances | |
| /// directly with its constructor. The <see cref="DbContext.OnConfiguring" /> method can then be overridden to | |
| /// configure a connection string and other options. | |
| /// </para> | |
| /// <para> | |
| /// Entity Framework Core does not support multiple parallel operations being run on the same <see cref="DbContext" /> | |
| /// instance. This includes both parallel execution of async queries and any explicit concurrent use from multiple threads. | |
| /// Therefore, always await async calls immediately, or use separate DbContext instances for operations that execute | |
| /// in parallel. See <see href="https://aka.ms/efcore-docs-threading">Avoiding DbContext threading issues</see> for more information | |
| /// and examples. | |
| /// </para> | |
| /// <para> | |
| /// See <see href="https://aka.ms/efcore-docs-di">Using DbContext with dependency injection</see> for more information and examples. | |
| /// </para> |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description "The default is 1024" is misleading. This parameter doesn't have a default value in the method signature (line 1100), so users must explicitly provide it. The documentation should say something like "Sets the maximum number of instances retained by the pool." without mentioning a default, or clarify that 1024 is what the underlying pool uses, not a parameter default.
| /// The maximum number of <typeparamref name="TContext" /> instances retained by the pool. | |
| /// The default is 1024. | |
| /// Sets the maximum number of <typeparamref name="TContext" /> instances retained by the pool. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| int poolSize) | |
| int poolSize = DbContextPool<DbContext>.DefaultPoolSize) |
and remove the other overload
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra blank line. According to EF Core coding guidelines, there should be no multiple consecutive blank lines. Line 1107 appears to be an extra blank line that should be removed.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Microsoft.EntityFrameworkCore.Internal; | ||
|
|
||
| namespace Microsoft.EntityFrameworkCore.Infrastructure; | ||
|
|
||
| public class AddPooledDbContextFactoryParameterlessTest | ||
| { | ||
| private sealed class TestDbContext : DbContext | ||
| { | ||
| public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) { } | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task Parameterless_factory_should_use_ConfigureDbContext_options() | ||
| { | ||
| var services = new ServiceCollection(); | ||
|
|
||
| services.ConfigureDbContext<TestDbContext>((sp, opts) => | ||
| opts.UseInMemoryDatabase("test_db")); | ||
|
|
||
| services.AddPooledDbContextFactory<TestDbContext>(); | ||
|
|
||
| using var provider = services.BuildServiceProvider(); | ||
| var factory = provider.GetRequiredService<IDbContextFactory<TestDbContext>>(); | ||
| await using var db = await factory.CreateDbContextAsync(); | ||
|
|
||
| Assert.Equal("Microsoft.EntityFrameworkCore.InMemory", db.Database.ProviderName); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task Parameterless_factory_with_custom_pool_size_should_still_resolve() | ||
| { | ||
| var services = new ServiceCollection(); | ||
|
|
||
| services.ConfigureDbContext<TestDbContext>((sp, opts) => | ||
| opts.UseInMemoryDatabase("test_db_custom_pool")); | ||
|
|
||
| services.AddPooledDbContextFactory<TestDbContext>(poolSize: 256); | ||
|
|
||
| using var provider = services.BuildServiceProvider(); | ||
| var factory = provider.GetRequiredService<IDbContextFactory<TestDbContext>>(); | ||
| await using var db = await factory.CreateDbContextAsync(); | ||
|
|
||
| Assert.Equal("Microsoft.EntityFrameworkCore.InMemory", db.Database.ProviderName); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Scoped_resolution_of_TContext_uses_pooled_factory() | ||
| { | ||
| var services = new ServiceCollection(); | ||
|
|
||
| services.ConfigureDbContext<TestDbContext>((sp, opts) => | ||
| opts.UseInMemoryDatabase("scoped_db")); | ||
|
|
||
| services.AddPooledDbContextFactory<TestDbContext>(); | ||
|
|
||
| using var provider = services.BuildServiceProvider(); | ||
|
|
||
| using var scope = provider.CreateScope(); | ||
| var ctx = scope.ServiceProvider.GetRequiredService<TestDbContext>(); | ||
| Assert.Equal("Microsoft.EntityFrameworkCore.InMemory", ctx.Database.ProviderName); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Pooled_services_are_registered_and_singleton() | ||
| { | ||
| var services = new ServiceCollection(); | ||
|
|
||
| services.ConfigureDbContext<TestDbContext>((sp, opts) => | ||
| opts.UseInMemoryDatabase("pool_reg_db")); | ||
|
|
||
| services.AddPooledDbContextFactory<TestDbContext>(); | ||
|
|
||
| using var provider = services.BuildServiceProvider(); | ||
|
|
||
| var pool1 = provider.GetRequiredService<IDbContextPool<TestDbContext>>(); | ||
| var pool2 = provider.GetRequiredService<IDbContextPool<TestDbContext>>(); | ||
|
|
||
| // Should be the same singleton instance | ||
| Assert.Same(pool1, pool2); | ||
|
|
||
| // And the factory should resolve | ||
| var factory = provider.GetRequiredService<IDbContextFactory<TestDbContext>>(); | ||
| Assert.NotNull(factory); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task Parameterless_factory_without_configuration_throws_meaningful_error() | ||
| { | ||
| var services = new ServiceCollection(); | ||
|
|
||
| // No ConfigureDbContext here on purpose. | ||
| services.AddPooledDbContextFactory<TestDbContext>(); | ||
|
|
||
| using var provider = services.BuildServiceProvider(); | ||
| var factory = provider.GetRequiredService<IDbContextFactory<TestDbContext>>(); | ||
| await using var db = await factory.CreateDbContextAsync(); | ||
|
|
||
| // Trigger provider requirement (any DB operation works; EnsureCreated is simple & provider-agnostic) | ||
| await Assert.ThrowsAsync<InvalidOperationException>(async () => | ||
| { | ||
| await db.Database.EnsureCreatedAsync(); | ||
| }); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing period at the end of the sentence. The line ends with
ServiceLifetime)"/>but should end withServiceLifetime)"/>.to be consistent with XML documentation style in the rest of the file.