-
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
Support arbitrary expressions in inline collections (translate to VALUES) #30734
Comments
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
Closes dotnet#30732 Closes dotnet#30734
The query above still fails: await context.Customers.Where(c => new[] { 2, 999, 1000 }.Count(i => i > c.Id) == 2).ToListAsync();
Full repro: using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
await using var context = new SmallStuff();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
// var (i, j) = (2, 999);
// await context.Customers.Where(c => new[] { i, j }.Contains(c.Id)).ToListAsync();
await context.Customers.Where(c => new[] { 2, 999, 1000 }.Count(i => i > c.Id) == 2).ToListAsync();
public class SmallStuff : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=SmallStuff")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
public DbSet<Customer> Customers => Set<Customer>();
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderDetail> OrderDetails => Set<OrderDetail>();
public DbSet<Product> Products => Set<Product>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderDetail>().HasKey(e => new { e.ProductId, e.OrderId });
}
}
public class Customer
{
public int Id { get; set; }
public required string Name { get; set; }
public string? Region { get; set; }
public List<Order> Orders { get; } = new();
}
public class Order
{
public int Id { get; set; }
public required string Name { get; set; }
public string? OrderRegion { get; set; }
public Customer? Customer { get; set; }
public List<OrderDetail> Details { get; } = new();
}
public class OrderDetail
{
public int ProductId { get; set; }
public int OrderId { get; set; }
public int Count { get; set; }
}
public class Product
{
public int Id { get; set; }
public required string Name { get; set; }
public List<OrderDetail> Details { get; } = new();
} |
Thanks, I'll take a look... There should be a test for the query in my OP, there must be some difference... |
@roji I searched for "Constant_Count_with_three_values", but it doesn't seem to exist. |
It was renamed to Inline_collection_Count_with_three_values, can be seen here. |
@ajcvickers your repro above works for me (using latest release/8.0), generating the following SQL: SELECT [c].[Id], [c].[Name], [c].[Region]
FROM [Customers] AS [c]
WHERE (
SELECT COUNT(*)
FROM (VALUES (CAST(2 AS int)), (999), (1000)) AS [v]([Value])
WHERE [v].[Value] > [c].[Id]) = 2 Can you take a look? There's also the test Inline_collection_Count_with_three_values which should cover this scenario. |
@ajcvickers can you take a look at this? |
@roji Yeah, I did look at this again and it was working for me, but I forgot to close it when I moved it back to the milestone. |
Our inline collection support currently supports constants:
While it's possible to also specify parameters, the NewArrayExpression gets client-evaluated by ParameterExtractingEV (because no database-correlated component), and so we get a single parameter for the array. This means we translate using OPENJSON, which isn't ideal - #30732 tracks doing a better translation to VALUES instead.
Beyond that, we could also allow arbitrary expressions:
The main blocker here is doing null semantics for InExpression over arbitrary expressions. Compensating to two-value logic isn't going to be easy...
The text was updated successfully, but these errors were encountered: