Skip to content
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

Make PooledDbContextFactory public (preview4) #24725

Merged
merged 1 commit into from
Apr 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 30 additions & 73 deletions src/EFCore/Extensions/EntityFrameworkServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ public static class EntityFrameworkServiceCollectionExtensions
/// </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContext>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder>? optionsAction = null,
Expand Down Expand Up @@ -102,9 +100,7 @@ public static IServiceCollection AddDbContext<TContext>(
/// </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder>? optionsAction = null,
Expand Down Expand Up @@ -149,16 +145,12 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextPool<TContext>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContext : DbContext
=> AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction, poolSize);

Expand Down Expand Up @@ -195,16 +187,12 @@ public static IServiceCollection AddDbContextPool<TContext>(
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContextImplementation : DbContext, TContextService
where TContextService : class
{
Expand Down Expand Up @@ -253,16 +241,12 @@ public static IServiceCollection AddDbContextPool<TContextService, TContextImple
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextPool<TContext>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContext : DbContext
=> AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction, poolSize);

Expand Down Expand Up @@ -308,16 +292,12 @@ public static IServiceCollection AddDbContextPool<TContext>(
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextPool<TContextService, TContextImplementation>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContextImplementation : DbContext, TContextService
where TContextService : class
{
Expand Down Expand Up @@ -381,9 +361,7 @@ private static void AddPoolingOptions<TContext>(
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContext>(
this IServiceCollection serviceCollection,
ServiceLifetime contextLifetime,
Expand Down Expand Up @@ -411,9 +389,7 @@ public static IServiceCollection AddDbContext<TContext>(
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
this IServiceCollection serviceCollection,
ServiceLifetime contextLifetime,
Expand Down Expand Up @@ -470,9 +446,7 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
/// </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContext>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
Expand Down Expand Up @@ -527,9 +501,7 @@ public static IServiceCollection AddDbContext<TContext>(
/// </param>
/// <param name="contextLifetime"> The lifetime with which to register the DbContext service in the container. </param>
/// <param name="optionsLifetime"> The lifetime with which to register the DbContextOptions service in the container. </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContext<TContextService, TContextImplementation>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
Expand Down Expand Up @@ -600,9 +572,7 @@ public static IServiceCollection AddDbContext<TContextService, TContextImplement
/// The lifetime with which to register the factory and options.
/// The default is <see cref="ServiceLifetime.Singleton" />
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextFactory<TContext>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder>? optionsAction = null,
Expand Down Expand Up @@ -659,9 +629,7 @@ public static IServiceCollection AddDbContextFactory<TContext>(
/// The lifetime with which to register the factory and options.
/// The default is <see cref="ServiceLifetime.Singleton" />
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder>? optionsAction = null,
Expand Down Expand Up @@ -727,9 +695,7 @@ public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
/// The lifetime with which to register the factory and options.
/// The default is <see cref="ServiceLifetime.Singleton" />
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextFactory<TContext>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
Expand Down Expand Up @@ -794,9 +760,7 @@ public static IServiceCollection AddDbContextFactory<TContext>(
/// The lifetime with which to register the factory and options.
/// The default is <see cref="ServiceLifetime.Singleton" />
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder>? optionsAction,
Expand Down Expand Up @@ -850,16 +814,12 @@ public static IServiceCollection AddDbContextFactory<TContext, TFactory>(
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddPooledDbContextFactory<TContext>(
this IServiceCollection serviceCollection,
Action<DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContext : DbContext
{
Check.NotNull(optionsAction, nameof(optionsAction));
Expand Down Expand Up @@ -898,16 +858,12 @@ public static IServiceCollection AddPooledDbContextFactory<TContext>(
/// will not be called.
/// </para>
/// </param>
/// <param name="poolSize">
/// Sets the maximum number of instances retained by the pool.
/// </param>
/// <returns>
/// The same service collection so that multiple calls can be chained.
/// </returns>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddPooledDbContextFactory<TContext>(
this IServiceCollection serviceCollection,
Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
int poolSize = 128)
int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
where TContext : DbContext
{
Check.NotNull(serviceCollection, nameof(serviceCollection));
Expand All @@ -916,7 +872,8 @@ public static IServiceCollection AddPooledDbContextFactory<TContext>(
AddPoolingOptions<TContext>(serviceCollection, optionsAction, poolSize);

serviceCollection.TryAddSingleton<IDbContextPool<TContext>, DbContextPool<TContext>>();
serviceCollection.TryAddSingleton<IDbContextFactory<TContext>, PooledDbContextFactory<TContext>>();
serviceCollection.TryAddSingleton<IDbContextFactory<TContext>>(
sp => new PooledDbContextFactory<TContext>(sp.GetRequiredService<IDbContextPool<TContext>>()));

return serviceCollection;
}
Expand Down
4 changes: 1 addition & 3 deletions src/EFCore/IDbContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Defines a factory for creating <see cref="DbContext" /> instances.
/// A service of this type is registered in the dependency injection container by the
/// <see cref="M:EntityFrameworkServiceCollectionExtensions.AddDbContextPool" /> methods.
/// </summary>
/// <typeparam name="TContext"> The <see cref="DbContext" /> type to create. </typeparam>
public interface IDbContextFactory<out TContext>
Expand All @@ -17,7 +15,7 @@ public interface IDbContextFactory<out TContext>
/// Creates a new <see cref="DbContext" /> instance.
/// </para>
/// <para>
/// The caller is responsible for disposing the context; it will not be disposed by the dependency injection container.
/// The caller is responsible for disposing the context; it will not be disposed by any dependency injection container.
/// </para>
/// </summary>
/// <returns> A new context instance. </returns>
Expand Down
5 changes: 5 additions & 0 deletions src/EFCore/Infrastructure/CoreOptionsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@ public virtual void ApplyServices(IServiceCollection services)
/// <param name="options"> The options being validated. </param>
public virtual void Validate(IDbContextOptions options)
{
if (MaxPoolSize.HasValue && MaxPoolSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(MaxPoolSize), CoreStrings.InvalidPoolSize);
}

if (_internalServiceProvider != null)
{
if (ReplacedServices != null)
Expand Down
54 changes: 54 additions & 0 deletions src/EFCore/Infrastructure/PooledDbContextFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.Internal;

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
/// <summary>
/// <para>
/// A factory returning pooled <see cref="DbContext" /> instances. Disposing the instance returned by this factory returns
/// them to the internal pooling mechanism.
/// </para>
/// <para>
/// A service of this type is registered in the dependency injection container by the
/// <see cref="M:EntityFrameworkServiceCollectionExtensions.AddDbContextPool" /> methods.
/// </para>
/// </summary>
public class PooledDbContextFactory<TContext> : IDbContextFactory<TContext>
where TContext : DbContext
{
private readonly IDbContextPool<TContext> _pool;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public PooledDbContextFactory(IDbContextPool<TContext> pool)
=> _pool = pool;

/// <summary>
/// Initializes a new instance of the <see cref="PooledDbContextFactory{TContext}" /> class.
/// </summary>
/// <param name="options"> The options to use for contexts produced by this factory. </param>
/// <param name="poolSize"> Sets the maximum number of instances retained by the pool. Defaults to 128. </param>
public PooledDbContextFactory(DbContextOptions<TContext> options, int poolSize = DbContextPool<DbContext>.DefaultPoolSize)
{
var optionsBuilder = new DbContextOptionsBuilder<TContext>(options);

var extension = (options.FindExtension<CoreOptionsExtension>() ?? new CoreOptionsExtension())
.WithMaxPoolSize(poolSize);

((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);

_pool = new DbContextPool<TContext>(optionsBuilder.Options);
}

/// <inheritdoc />
public virtual TContext CreateDbContext()
=> (TContext)new DbContextLease(_pool, standalone: true).Context;
}
}
Loading