-
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
SQL aliases aren't uniquified in ExecuteUpdate setters #31078
Comments
I am not able to reproduce this--see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate. using (var context = new SomeDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
int code = 1;
var workQuery = context.WorkOrders.Where(x => x.OrderCode == code);
await context.Set<BomItem>()
.Where(x => x.OrderCode == code)
.ExecuteUpdateAsync(x =>
x.SetProperty(s => s.HasWorkOrder, b => workQuery.Where(o => o.BomItemId == b.Id).Any()));
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
public DbSet<WorkOrder> WorkOrders => Set<WorkOrder>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BomItem>();
}
}
public class WorkOrder
{
public int Id { get; set; }
public int OrderCode { get; set; }
public int BomItemId { get; set; }
}
public class BomItem
{
public int Id { get; set; }
public int OrderCode { get; set; }
public bool HasWorkOrder { get; set; }
}
|
We are seeing this on both SQL Server and PostgreSQL: using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using (var context = new ExampleDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var id = Guid.NewGuid();
await context.Orders
.Where(o => o.Id == id)
.Select(o => new
{
Order = o,
Total = o.OrderProducts.Sum(op => op.Amount * op.TotalCost)
})
.ExecuteUpdateAsync(e => e
.SetProperty(x => x.Order.Total, x => x.Total));
}
public class ExampleDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=test")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderProduct> OrderProducts => Set<OrderProduct>();
}
public class Order
{
public Guid Id { get; set; }
public decimal Total { get; set; }
public ICollection<OrderProduct> OrderProducts { get; set; } = new List<OrderProduct>();
}
public class OrderProduct
{
public Guid Id { get; set; }
public int Amount { get; set; }
public decimal TotalCost { get; set; }
} Output for SQL Server:
Both Output for PostgreSQL:
EF Core version: 7.0.8 If I change the name of the table, it works:
|
@KernelCrap referencing navigations within the ExecuteUpdate currently supported; see these docs which include the workaround. |
@roji The example is using the method described in your link. |
@KernelCrap I'm seeing the following in your code sample: .ExecuteUpdateAsync(e => e
.SetProperty(x => x.Order.Total, x => x.Total));
|
@roji Here is the example from the documentation: context.Blogs
.Select(b => new { Blog = b, NewRating = b.Posts.Average(p => p.Rating) })
.ExecuteUpdate(setters => setters.SetProperty(b => b.Blog.Rating, b => b.NewRating)); It is supported when using |
@ajcvickers |
@hexianggui In your new project, your tables are named From my testing, it breaks when two tables use the same prefix. In my example, before my comment was hidden, I experienced the same thing with two tables named |
@KernelCrap Yes, you are right. Thank you very much! I added a prefix and now I have successfully reproduced the previous issue! exampleProject
Furthermore, to maintain consistency with the original project environment, I built the project using ABPvNext. I have not conducted any testing to determine if the same results can be achieved without using any additional frameworks. |
I haven't read the source code, but based on the above observations, it appears that table aliases are derived from the initial letter of the table name. For example, the aliases for "BomItem" and "WorkOrder" are "b" and "w" respectively, while the aliases for "MesBomItem" and "MesWorkOrder" are both "m". If that's the case, having two or more table names with the same initial letter in the same SQL statement can lead to confusion. |
@KernelCrap apologies, I read your code sample too quickly. I can see the error happening, we'll investigate this. |
Reopening to consider patching. |
@roji Note from triage: patch. |
Fixes dotnet#31078 (cherry picked from commit 8e4acf4)
Fixes dotnet#31078 (cherry picked from commit 8e4acf4)
Patch PR: #31208 |
Thanks for this fix! |
I use ExecuteUpdateAsync to update data, but it seems that the generated SQL statement has a problem. Here is the code:
The incorrect SQL statement is:
The correct SQL statement should be:
EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET 7.0
Operating system:
IDE: Visual Studio 2022 17.6
The text was updated successfully, but these errors were encountered: