-
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
The order of ExecuteUpdate setters is not preserved #35361
Comments
The plot thickens... It turns out that in most databases, the setters always see the row as it was before any updates were made to it; this means that the order of setters is irrelevant: DROP TABLE IF EXISTS foo;
CREATE TABLE foo (a int, b int);
INSERT INTO foo (a, b) VALUES (0, 0);
UPDATE foo SET a = 10, b = a + 1;
SELECT b FROM foo; The above returns 1 rather than 11 for most databases (SQL Server, PostgreSQL, SQLite). However, MySQL and MariaDB return 11, meaning that the previous setter is taken into account when evaluating the later setter; ordering matters there. Note that current EF simply inverses the setters, so as a workaround users can simply inverse themselves, starting with the last. I've taken a look, and this is fixed in #35257, which should get merged shortly. @lauxjpn it would be great if you could add a test on your side to confirm this, something like: [ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Update_Where_set_ordering_is_preserved(bool async)
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
Fixture.CreateContext, Fixture.UseTransaction,
async context =>
{
var updated = await context.Set<Customer>().ExecuteUpdateAsync(
setters => setters
.SetProperty(c => c.ContactName, "X")
.SetProperty(c => c.ContactTitle, c => c.ContactName + "Y"));
Assert.True(updated > 0);
Assert.Equal(updated, await context.Set<Customer>().CountAsync(c => c.ContactTitle == "XY"));
updated = await context.Set<Customer>().ExecuteUpdateAsync(
setters => setters
.SetProperty(c => c.City, "Y")
.SetProperty(c => c.ContactName, c => c.City + "X"));
Assert.True(updated > 0);
Assert.Equal(updated, await context.Set<Customer>().CountAsync(c => c.ContactName == "YX"));
}); |
@roji MS Access returns 1 so no issue there either |
For the following ExecuteUpdate:
... we generate the following SQL:
Note that the SQL order of the setters is reversed; this is important, as there can be a dependency between the setters. We should preserve the original LINQ ordering.
Originally flagged in PomeloFoundation/Pomelo.EntityFrameworkCore.MySql#1776
Full repro
The text was updated successfully, but these errors were encountered: