diff --git a/entity-framework/core/dbcontext-configuration/index.md b/entity-framework/core/dbcontext-configuration/index.md index 55d3738ccb..ffec36c8a7 100644 --- a/entity-framework/core/dbcontext-configuration/index.md +++ b/entity-framework/core/dbcontext-configuration/index.md @@ -2,7 +2,7 @@ title: DbContext Lifetime, Configuration, and Initialization - EF Core description: Patterns for creating and managing DbContext instances with or without dependency injection author: SamMonoRT -ms.date: 11/07/2020 +ms.date: 09/30/2025 uid: core/dbcontext-configuration/index --- @@ -309,6 +309,8 @@ The following table contains examples of common methods called on `DbContextOpti | | More detailed query errors (at the expense of performance) | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) | | Ignore or throw for warnings and other events | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) | | Registers EF Core interceptors | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) +| | Controls caching of the internal service provider | [Service Provider Caching](#service-provider-caching) +| | Configures the memory cache used by EF Core | [Memory Cache Integration](#memory-cache-integration) | | Use dynamic proxies for lazy-loading | [Lazy Loading](xref:core/querying/related-data/lazy) | | Use dynamic proxies for change-tracking | Coming soon... @@ -423,6 +425,48 @@ Any code that explicitly executes multiple threads in parallel should ensure tha Using dependency injection, this can be achieved by either registering the context as scoped, and creating scopes (using `IServiceScopeFactory`) for each thread, or by registering the `DbContext` as transient (using the overload of `AddDbContext` which takes a `ServiceLifetime` parameter). +## EnableServiceProviderCaching + +EF Core uses an internal service provider to manage services required for database operations, including query compilation, model building, and other core functionality. By default, EF Core caches these internal service providers to improve performance when multiple `DbContext` instances share the same configuration. + +The method controls whether EF Core caches the internal service provider: + +```csharp +public class ApplicationDbContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder + .EnableServiceProviderCaching(false) + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"); + } +} +``` + +**Default behavior**: Service provider caching is **enabled by default** (`true`). This means: + +- Service providers are cached and reused across `DbContext` instances with the same configuration +- Better performance for applications that create many `DbContext` instances +- Lower memory overhead when multiple contexts share configurations + +**When to disable caching**: Disabling service provider caching will greatly slow down `DbContext` creation and in the vast majority of cases the default behavior is recommended. If there are issues with incorrect internal services used, then they should be fixed in a different way. But if you are replacing services for testing purposes you could disable service provider caching (`false`) to ensure each test gets a fresh service provider. + +## Memory Cache Integration + +EF Core integrates with ASP.NET Core's memory caching infrastructure through `IMemoryCache`. However, this is not used for the internal service provider caching described above. + +EF Core automatically configures `IMemoryCache` with a default size limit of 10240 for internal caching operations such as query compilation and model building. You should call `AddMemoryCache` if you need to change these defaults. For reference, a compiled query has a cache size of 10, while the built model has a cache size of 100. + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddMemoryCache(options => options.SizeLimit = 20480); // Custom size limit for EF Core caching + + services.AddDbContext(options => + options.UseSqlServer(connectionString)); +} +``` + ## More reading - Read [Dependency Injection](/aspnet/core/fundamentals/dependency-injection) to learn more about using DI. diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index bcd662ae1f..575da40749 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -151,6 +151,9 @@ Note that there is no need to parameterize each and every query: it's perfectly > [!NOTE] > EF Core's [metrics](xref:core/logging-events-diagnostics/metrics) report the Query Cache Hit Rate. In a normal application, this metric reaches 100% soon after program startup, once most queries have executed at least once. If this metric remains stable below 100%, that is an indication that your application may be doing something which defeats the query cache - it's a good idea to investigate that. +> +> [!TIP] +> EF Core uses `IMemoryCache` for internal caching of compiled queries and models. You can configure the cache size limit if needed - see [Memory Cache Integration](xref:core/dbcontext-configuration/index#memory-cache-integration) for more information. > [!NOTE] > How the database manages caches query plans is database-dependent. For example, SQL Server implicitly maintains an LRU query plan cache, whereas PostgreSQL does not (but prepared statements can produce a very similar end effect). Consult your database documentation for more details.