-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Support SELECT FOR UPDATE / UPDLOCK (pessimistic concurrency) #26042
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
Comments
This may be covered by #6717, and may be achievable today by using raw SQL and composing your LINQ operators over it (see the docs), assuming SQL Server allows SELECT FOR UPDATE in a subquery. |
Note: use table annotations to represent this (#26858). |
Cross-database investigation on
|
Another use case is |
For anyone who can't wait for this feature, check out this simple command interceptor or try Linq2Db. |
Another use-case: atomically update something with ExecuteUpdate. This can be done today with optimistic locking, but that requires retrying when the update fails; that means some sort of random delay + backoff strategy is needed, where pessimistic locking can solve this much more easily. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hello everyone, I’ve reviewed this issue and would like to contribute by implementing support for SELECT FOR UPDATE in EF Core. This functionality is critical for scenarios requiring pessimistic concurrency control, ensuring that rows are locked for updates and preventing conflicts in multi-transaction environments. Proposed Approach:
Next Steps:
Looking forward to contributing and helping bring this feature to the community! Please let me know if you have any feedback or additional suggestions. Best regards, |
Hi nimanikoo, thanks for taking the initiative! Supporting SELECT FOR UPDATE — especially with options like SKIP LOCKED and NOWAIT — would indeed be a great addition for scenarios involving high-concurrency workloads. Just a few probably obvious PostgreSQL-specific notes that might help with implementation (just in case): PostgreSQL Considerations Suggestions Looking forward to seeing your PR! |
@nimanikoo I really appreciate the offer to work on this and the enthusiasm; however, it's important to point out that pessimistic locking is quite a big feature which would involve some potentially deep changes in the EF query pipeline - which is complex. If you don't have any prior experience with the query pipeline and/or this is your first (big) contribution to EF, I'd advise trying to work on something simpler first. More concretely on your proposal: var entity = context.MyEntities
.Where(e => e.Id == 1)
.SelectForUpdate(skipLocked: true) // Example usage
.FirstOrDefault(); Note that FOR UPDATE/UPDLOCK are table-scoped, and not query-scoped; in other words, different tables in the query can have different pessimistic locking settings. You'd need to think about what that means for your proposed API, and how users express different settings for different tables. Finally, I'd be curious to hear about why pessimistic locking is necessary in your scenario, and why EF's optimistic concurrency is insufficient. The latter seems to work well enough for the vast majority of cases, which is also why we haven't been prioritizing this. |
hello again @roji , Thanks a lot for your detailed response — I really appreciate your insights and the time you took to outline the challenges and considerations involved. To clarify my motivation and scenario: I'm currently using EF Core 8 with PostgreSQL. In one of our high-concurrency flows, I need to lock only a single row using This level of control is essential to ensure correctness in scenarios like payment processing or job scheduling, where race conditions can have serious consequences. Using While I haven't contributed to EF Core yet, I’d love to get involved. I’ve contributed to large open-source projects such as OpenTelemetry and RedisStack, and I’m confident in my ability to help with complex features — especially with guidance and support from the team. I completely understand this is a non-trivial change, and I don’t expect to do it in isolation. If this is too large for a first contribution, I’d be very happy to work on smaller issues first to build up context. But if there’s any chance to contribute to this feature — even incrementally or starting with a provider-specific prototype — I’d be excited to collaborate. Please let me know if there’s any issue you’d recommend as a good starting point. Either way, I’d love to be involved and contribute meaningfully to EF Core. Thanks again for your time! Best regards, |
That's very understandable, but my question is more where you feel you need pessimistic locking, as opposed to the optimistic row locking that EF already supports well; the latter is not a table-level lock, but rather a different approach to handling concurrent loads. In some cases, people are simply unaware of optimistic locking (or misunderstand it) and assume that they must use As to contributing... The team unfortunately has limited capacity at the moment to guide complex, large-scale contributions (which this would be) - I wouldn't want you to do a lot of work, and then for the PR to sit for a long time since we have other priorities. If you're OK with taking this risk, then I'd suggest you take a look at the codebase, and put together a more detailed plan of exactly which types you're proposing to change and how (because your above comment only contains a very high-level overview). I'd also want to know how you plan to handle the case I mentioned above of multiple tables (and subqueries) within the same query. |
My team needed pessimistic locking when implementing a transactional outbox pattern. Optimistic locking won't work and will result in a duplicate event publishing when the app is running in multiple instances. Also, any scenario that requires calling an external service won't be covered by optimistic locking e.g var notification = _dbContext.Notification.First();
if(notification.Completed)
{
return;
}
notification.SetCompleted();
// Nothing prevents two callers from executing this method twice with optimistic concurrency
// even though one of the callers will error out, we can't unsend the email or undo external operation
_externalService.NotifyWithEmail(notificaton.Id);
_dbContext.SaveChanges(); The above problem is solved by outbox, but in the scenarios where it would be overkill, we don't have an option to simply use pessimistic locking without writing raw SQL. |
I want to garantee that only one Api Request (Database Transaction) can modify an entity at a given time. this could be done by selecting a row with "SELECT FOR UPDATE" inside a transaction.
Something like:
Would generate something like:
I think that EF itself does not need to track at any level that the entity was selected with a table hint, it only need to be able to express the SQL.
The text was updated successfully, but these errors were encountered: