-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Allow opt-out of optimistic concurrency/rows affected check in the model #10443
Comments
@jsacapdev EF Core currently expects the rows affected returned to match what is expected to happen in the database based on the model and conceptual operation being performed. In cases like this where a trigger is being used and the conceptual operation is being changed it would be useful to be able to opt out of this checking. For Adds specifically, see also #7038 |
@jsacapdev does it work if you follow the recommendation to add CREATE TRIGGER RemoveTestPosts
ON [dbo].[Posts]
FOR INSERT
AS
SET NOCOUNT ON;
DELETE FROM [dbo].[Posts] WHERE Content = 'test1';
GO |
@Suchiman setting nocount on does not work @ajcvickers would you be open to accepting a PR to get this fixed? I ask as you may need to consider the impact of the change required. If you are open to accepting a PR, we can start to discuss your thoughts on a design moving forward? |
@jsacapdev Yes, we would certainly consider a PR for this. I'll get back to you on a potential approach. |
We discussed this and came to the following initial conclusions:
As of now, we haven't settled on the API questions, so marking this issue as needs-design. @jsacapdev If you only need this for inserts, then I would suggest tackling #7038 since this doesn't require API changes. If you need this for updates and deletes as well, then we're going to have to do more design work, and this may take some time. Also, we are surprised that using SET NOCOUNT ON does not work--can you provide any more details on why this doesn't work? |
@ajcvickers What I have found is that with both triggers (with and without NOCOUNT) I dont get a PostId returned when either query is generated and executed on the database. So the logic in ConsumeResultSetWithPropagation() that checks for a populated data reader fails and it throws back with the same behaviour.
|
@jsacapdev Can you explain more about what the scenarios are for using the triggers? (If, for example, the result of doing the insert is that the record doesn't exist after the insert, then this is going to be very hard for EF to reason about. However, it seems likely that the real reason for using the trigger is something different, so we'd like to understand more. |
@ajcvickers if i am honest, its not a very general use case, and its just as simple as understanding why once a triggered has been fired do i get an exception throw back. i appreciate your time looking into this and the information you have provided. and i have learnt a little bit more about the product. |
@ajcvickers I am having the same issue with my "UPSERT" trigger. Weirdly enough, my error
Odd note, inserting test data from VS code returns 1 row affected, with the trigger catching and updating it. Trigger code:
|
@AndriySvyryd @divega Should we document what the update pipeline expects back for the various cases? For example, if EF is doing an insert in batch mode and there are store-generated values coming back. |
The issue I'm having with INSTEAD OF INSERT triggers is that Entity Framework is batching the insert statement with a select statement using Perhaps an option to have inserts use |
I have INSTEAD OF INSERT trigger too - just collecting some third-party ad-hoc data and in the instead-of-trigger having logic avoiding duplications via unique key doing actually a data merge - insert or update. In fact there is no transactional concurrency - third-party data are collected just-in-time - storing only needed ones, not PRE-IMPORTING all the third-party entities before running an application. I thought using ALTERNATE (composed) KEY would be the way, but not: there is still
@@rowcount is 1, but scope_identity is NULL. May be using alternate key in the way:
could be easy to implement? |
Note an important perf aspect here: optimistic concurrency checks are a blocker for #27532; we can't insert the commit into the batch, since we need to throw and roll back if there's a concurrency exception, but we only know that on the client after the transaction gets committed. So we must do an additional roundtrip, which has a cost. |
See Twitter poll specifically about the deletion question (also discussed in #27562). Some reason why concurrency checks around deletion can be useful:
|
We've had various discussions around this recently, here's a summary.
|
Another good reason to opt out of EF's optimistic concurrency is if you're using repeatable read transactions (or serializable/snapshot). Repeatable read transactions are somewhat similar to optimistic concurrency, but managed by the database instead of by EF: the unit-of-work only succeeds if there was no conflict, otherwise an error is raised and the application has to retry. Serializable/snapshot transactions have overhead costs which vary across databases (e.g. may introduce additional locking), and also provide more than just checking that rows haven't changed (e.g. they guarantee a stable view of the database throughout the transaction). |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Another use case that is affected by this DbUpdateConcurrencyException is updating a disconnected entity that does not exist. Opting out of this behavior and reading the rows updated would be a much better solution than catching every DbUpdateConcurrencyException. |
A trigger is created on the database to delete an row if it meets some condition.
An entity is added to the table that matches that condition.
The call to SaveChanges() throws.
Is this by design? Is there a workaround? (other than using a third party library)
Steps to reproduce
Ran the program to create a Blog.
Ran the program to create a post.
Manually created the trigger.
Ran the program again to create a post.
Further technical details
EF Core version:
Microsoft.AspNetCore.All 2.0.3
Microsoft.EntityFrameworkCore 2.0.1
Database Provider:
Microsoft.EntityFrameworkCore.SqlServer
SQL Server is running in docker
Operating system:
Visual Studio Code
Dotnet:
PS C:\playground\AlrightTrigger\AlrightTriggerConsole> dotnet --info
.NET Command Line Tools (2.0.3)
Product Information:
Version: 2.0.3
Commit SHA-1 hash: 12f0c7efcc
Runtime Environment:
OS Name: Windows
OS Version: 10.0.14393
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.0.3\
Microsoft .NET Core Shared Framework Host
Version : 2.0.3
Build : a9190d4a75f4a982ae4b4fa8d1a24526566c69df
The text was updated successfully, but these errors were encountered: