-
Notifications
You must be signed in to change notification settings - Fork 2k
Document EnableServiceProviderCaching and UseMemoryCache configuration in EF Core #5116
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 9 commits
792d564
1014d1c
6019d54
2c3e7ec
6320f70
2d0367f
c339028
06b0933
705ef58
c0ef001
096438d
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 |
|---|---|---|
|
|
@@ -309,6 +309,8 @@ The following table contains examples of common methods called on `DbContextOpti | |
| | <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableDetailedErrors*> | More detailed query errors (at the expense of performance) | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) | ||
| | <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.ConfigureWarnings*> | Ignore or throw for warnings and other events | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) | ||
| | <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.AddInterceptors*> | Registers EF Core interceptors | [Logging, Events, and Diagnostics](xref:core/logging-events-diagnostics/index) | ||
| | <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableServiceProviderCaching*> | Controls caching of the internal service provider | [Service Provider Caching](#service-provider-caching) | ||
| | <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseMemoryCache*> | Configures the memory cache used by EF Core | [Memory Cache Integration](#memory-cache-integration) | ||
| | <xref:Microsoft.EntityFrameworkCore.ProxiesExtensions.UseLazyLoadingProxies*> | Use dynamic proxies for lazy-loading | [Lazy Loading](xref:core/querying/related-data/lazy) | ||
AndriySvyryd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| | <xref:Microsoft.EntityFrameworkCore.ProxiesExtensions.UseChangeTrackingProxies*> | Use dynamic proxies for change-tracking | Coming soon... | ||
|
|
||
|
|
@@ -423,6 +425,62 @@ 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm conflicted about this sort of documentation. Yes, we have EnableServiceProviderCaching() as a public API, but this is something that I think we'd never recommend users ever actually use So I'm not sure whether (and why) we should actually be documenting this - it runs the risk of pushing people towards an API they shouldn't use, it makes this doc page less useful (since it gets bloated with a non-useful API), and it creates more work for us (writing/reviewing the docs). If we believe there are legitimate reasons for users to use this (I'm not really aware of any), then these should be documented here. There's just one sentence below: "for testing environments to ensure each test gets a fresh service provider when
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not documenting API to discourage its use is not a good strategy. We've seen that even pubternal API without XML docs will get used if the users this they need it. I think that explaining the appropriate use cases and downsides is valuable and is more likely to reduce incorrect usage.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that there should be good xmldocs (hopefully there are), but I don't think what you say holds for conceptual docs. A user sees xmldocs for an API once they're already using (or considering using) that API, so it's important for that to be there, and properly explain things. In contrast, conceptual documentation is how users discover an API: before they come to this "DbContext configuration" page, they're 99% unaware that EnableServiceProviderCaching even exists, and this PR will make them aware of it. The main question IMHO is whether you think this API makes sense for more than 1% of EF users - I don't see that it does. Assuming we agree on that, and this API is indeed a pit of failiure for the 99% case, we're doing our users a disservice by talking about it and making them aware of it. It may have been a mistake to even introduce this API, but then we'd be compounding that mistake by marketing it here, mostly in the name of an "all APIs should be documented in conceptual docs" rule. An additional reason to not document this, is that every additional paragraph in the conceptual docs makes them less useful. We already have a history of falling into this, producing pages which are so huge that nobody even starts reading them - all the in the name of completeness/exhaustiveness, or the fear of being accused of having neglected to document something. I don't believe that's a good way to write docs. If I've misunderstood and you actually think that disabling service provider caching is useful for some non-contrived, non-edge-casey scenarios, let me know (the above is written with that assumption).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a valid scenario to use this in testing. We occasionally get questions about it, and I don't want to keep repeating the answer. I can move this to a new page under https://learn.microsoft.com/en-us/ef/core/testing/ to reduce length and visibility |
||
|
|
||
| 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. | ||
AndriySvyryd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.EnableServiceProviderCaching*> method controls whether EF Core caches the internal service provider: | ||
|
|
||
| <!-- | ||
| public class ApplicationDbContext : DbContext | ||
| { | ||
| protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | ||
| { | ||
| optionsBuilder | ||
| .EnableServiceProviderCaching(false) | ||
| .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"); | ||
| } | ||
| } | ||
| --> | ||
| [!code-csharp[EnableServiceProviderCaching](../../../samples/core/Miscellaneous/CompiledModels/BlogsContext.cs?range=18-22&highlight=2)] | ||
AndriySvyryd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| **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 | ||
AndriySvyryd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - Better performance for applications that create many `DbContext` instances | ||
| - Lower memory overhead when multiple contexts share configurations | ||
|
|
||
| **When to disable caching**: You might want to disable service provider caching (`false`) for testing environments to ensure each test gets a fresh service provider when `DbContext` configurations change test-to-test. | ||
AndriySvyryd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```csharp | ||
| public void ConfigureServices(IServiceCollection services) | ||
| { | ||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options | ||
| .UseSqlServer(connectionString) | ||
| .EnableServiceProviderCaching(true)); // Default, but shown for clarity | ||
AndriySvyryd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| ``` | ||
AndriySvyryd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Memory Cache Integration | ||
AndriySvyryd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 => | ||
| { | ||
AndriySvyryd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| options.SizeLimit = 20480; // Custom size limit for EF Core caching | ||
| }); | ||
|
|
||
| services.AddDbContext<ApplicationDbContext>(options => | ||
| options.UseSqlServer(connectionString)); | ||
| } | ||
| ``` | ||
|
|
||
| ## More reading | ||
|
|
||
| - Read [Dependency Injection](/aspnet/core/fundamentals/dependency-injection) to learn more about using DI. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.