-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Add hook to allow actions on the context after it is leased/returned from/to the pool #17086
Comments
Or, at least when used with ASP.NET Core, it could work like this, with a generic
Where |
I fail to see any filter or predicate in any of above examples. A filter/predicate in linq is a func which returns bool like |
@MorenoGentili If a query filter references a property on the context instance, and if the correct value is set when the instance is resolved from D.I., then the query filter should work correctly. So it's not clear to us what your proposal is addressing. |
@ajcvickers Please clarify this: when using DbContext pooling, is a In my scenario, HTTP requests come from multiple tenants. I'm afraid a DbContext instance that's been configured with a global filter for TenantId=1 will get reused for another tenant. @smitpatel I know and that's why this is a feature request. |
@MorenoGentili - If you plan to use query filter then where is the filter? |
@smitpatel A filter would be automatically configured for me by EFCore. A simple filter such as
And then
I'm sorry. I still don't understand. Let's read the documentation.
If a tenant id has to come from an instance field, and if Thanks |
Of course. Isn't that the purpose of pooling? You cannot use DbContext pooling if your DbContext is depending on services which cannot be reused across HTTP requests. |
Ok, thank you for the clarification. Now I'm going back to my original question: would you implement a feature that lets a pooled DbContext depend on services that cannot be reused across requests? The |
I don't think it could work that way. How do you expect us to retrieve the value when executing a query? Especially if it depends on a service which is outside the scope of EF. Or other way to put forward is, you need to put a new instance of your service each time after you get the context from pool. There is no bridge to EF Core query which makes it happen. (Even if we want to add what you are saying, we cannot). |
I'm not sure because I'm not too familiar with the internals of EFCore. I thought that maybe it could be possible since I can already resolve services from inside a DbContext instance by using this syntax.
However, I can understand the problem and now I wonder if it would be possible to at least expose an event or a protected overridable method, so I could execute code as soon as the DbContext instance has been retrieved from the pool and it's about to be used by services scoped to the current HTTP context. So I could update the private field like this:
Is this possible? And finally:
Indeed, if nothing else is possible I'd have to resort to that solution. Thanks for your insight on the issue. |
@MorenoGentili Taking a step back for a moment, I would like to make a few general points:
Having said all that, a hook that is called after the context is obtained from the pool is a reasonable idea; we'll certainly consider this. |
Thank you @ajcvickers, I will use that hook to update the
Any opinion about this? Would it work? |
@MorenoGentili I think so, but I'm not 100% sure. |
See also #19193 when working on this. Also, removing from backlog to consider again in triage. |
Coming over to this issue from npgsql/npgsql#2885 Considering my specific use-case of setting
To be honest, if there are no issues with DbContextPooling when using services.AddDbContextPooling(o ->
{
o.UseNpgsql(MyConnectionString);
}); it should be semantically no different from, services.AddDbContextPooling(o ->
{
var connection = new NpgsqlConnection(MyConnectionString);
o.UseNpgsql(connection);
}); Isn't it? Should I consider this a bug ..? |
It should not be hard to factor things so this is not the case.
Two things. First, context pooling is not connection pooling. You'll still be using pooled actual connections to the database through normal ADO.NET connection pooling. Second, the impression I got from the other thread was that you wanted to use a new scoped DbConnection object for each request. If you don't need to do that, then you could manipulate the existing connection object.
The point of context pooling is that it lets you create and configure a DbContext once and then re-use it for multiple requests. Therefore, it is by-design that the code to resolve, create, and configure the context will only run once for a given context instance. If an object is created in that process, then that object will be reused. |
This is what I want to do. I confused a DbConnection object with a physical pooled db connection. (They are handled separately right?) Edit: hmm... if this feature is still open... then it will be implemented for EFCore 3.1 .... but I'm still on EFCore 2.2 ... D: |
…e pool. Fixes #19193 Fixes #17086 Notes: * We now no longer reset context events, as per #19193 * However, I left the code that resets options like QueryTrackingBehavior since that still seems useful, and makes this less of a break * Added events to DbContext. These are easy and decoupled, but sync only. * A derived DbContext can override the On... event methods. This allows async hooks. * DbContextFactory now has a CreateDbContextAsync method such that a context can be rented from the pool and the hook applied in an async context.
…e pool. Fixes #19193 Fixes #17086 Notes: * We now no longer reset context events, as per #19193 * However, I left the code that resets options like QueryTrackingBehavior since that still seems useful, and makes this less of a break * Added events to DbContext. These are easy and decoupled, but sync only. * A derived DbContext can override the On... event methods. This allows async hooks. * DbContextFactory now has a CreateDbContextAsync method such that a context can be rented from the pool and the hook applied in an async context.
#24768 originally added events and overridable methods as hooks for actions on leasing/returning, but we punted on that for 6.0. Next step is for me to bring this to a design discussion, with the alternative approach of handling these hooks via the factory instead. |
Hello,
this issue is somewhat related to #14625 but I'd like to suggest something slightly different.
Basically, I need global filter values to be resolved on a per-request basis, even if the
DbContext
instance comes from the pool. Please, let's not discuss performance gains here, like in #14625, and just assume my app DOES benefit from using the pool.Here's my suggestion for a new overload of the
HasQueryFilter
API.First, I'd register a global filter in the
OnModelCreating
like this. Please note no actual value is provided here, but just a link between theTenantId
property of an entity class and a string identifier such as "TenantId".Then, each time a DbContext is needed (e.g. user sending a request), the identifier "TenantId" has to be resolved to an actual value. So, I would need to add a method to the
DbContext
to do just that. Maybe marked by an atttribute such asGlobalFilterResolverAttribute
. Please note this method must be dependency injection enabled so I can get a reference to scoped services like theITenantProvider
here.What do you think?
Thanks for your attention.
Moreno
The text was updated successfully, but these errors were encountered: