-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Concurrency token checks in Update and Delete methods of InMemoryTable #10158
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
Conversation
@shaynevanasperen, It will cover your contributions to all .NET Foundation-managed open source projects. |
@shaynevanasperen, thanks for signing the contribution license agreement. We will now validate the agreement and then the pull request. |
@@ -128,4 +128,7 @@ | |||
<data name="UpdateConcurrencyException" xml:space="preserve"> | |||
<value>Attempted to update or delete an entity that does not exist in the store.</value> | |||
</data> | |||
<data name="UpdateConcurrencyTokenException" xml:space="preserve"> | |||
<value>A conflict was detected on one or more properties configured as a concurrency token.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We always try to include information about which properties caused the conflict.
It would also be useful to tell people what the conflicting values are, but only if sensitive data logging is enabled. However, I think we would still take the PR without this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajcvickers Thanks for your feedback. I've now updated it to include this information.
@@ -89,6 +105,18 @@ public virtual void Update(IUpdateEntry entry) | |||
} | |||
} | |||
|
|||
private static bool ValueEquality(object val1, object val2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the scenario that requires this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajcvickers I'd imagine it would be every scenario? The reason is that when comparing boxed value types, they are not automatically considered equal, even if the values "inside the boxes" are equal. I got the code snippet from this Stack Overflow post: https://stackoverflow.com/questions/6668697/boxed-value-type-comparisons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shaynevanasperen Looks like this would only be an issue where comparing different types that have been boxed. Does this happen in the in-memory provider? If so, is there a test that fails or can one be written? (It's not that this is necessarily bad, but we have lots of code that rely on exact type comparisons, often in dynamically compiled code, so I would like to understand more clearly why this is needed in case is is masking a more fundamental bug.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajcvickers Without this, my code doesn't work and always throws the DbUpdateConcurrencyException
. Most of the existing tests in EFCore.Specification.Tests/UpdatesTestBase.cs fail without this code (when running the EFCore.InMemory.FunctionalTests/UpdatesInMemoryTest.)
Like this one for instance:
https://github.com/aspnet/EntityFrameworkCore/pull/10158/files#diff-125fbbaa7088e78da7b5c772bb2ddb65R35
In that case it is comparing a boxed decimal to another boxed decimal and even when the values are the same the equality check fails, so I had to write this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shaynevanasperen I pulled your code and changed ...en && !ValueEquality(_ro...
in both places to ...en && !Equals(_ro...
, commented out the ValueEquality method, and all the tests pass for me. It would be great to figure out why we are seeing different behavior here, since the rest of the PR looks great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajcvickers That's bizarre! I originally wrote it as ...en && _rows[key][index] != entry.GetOriginalValue(properties[index])
, but that didn't work.
Isn't x != y
functionally equivalent to !Equals(x, y)
?
I'll see if I can reproduce it now and then get back to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops! I feel so silly now. x != y
is a reference equality check. For some reason, I wrongly thought that if falls back to doing a value equality check if the reference equality check returns false
. In fact it is the other way around. A value equality check first does a reference equality comparison and then falls back to value comparison.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajcvickers I've just updated the code to use ...en && !Equals(_ro...
in both places, and I've removed the ValueEquality method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Se inline comments:
- Add at least property names to the exception message
- Clarify the use of converting equality code
8aa1146
to
5bb241a
Compare
5bb241a
to
544d97b
Compare
Thanks for the contribution! |
Uh oh!
There was an error while loading. Please reload this page.