-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
EF Core 8 Query Translation Bug: Array operations with union #33258
Comments
This also happens if we try using |
tl;dr confirmed, regression on EFCore.PG (the scenario wasn't working on other providers, since primitive collections weren't supported before 8.0). As a workaround, move the Where into the two set operation legs - while it doesn't look as good, it produces the same results and should have the same performance: _ = context.objs1.Where(o => o.Ints.Contains(8)).Select(o => o.Ints)
.Concat(context.objs2.Where(o => o.Ints.Contains(8)).Select(o => o.Ints))
.ToList(); Bug analysisFor the query: _ = context.objs1.Select(o => o.Ints)
.Concat(context.objs2.Select(o => o.Ints))
.Where(o => o.Contains(8))
.ToList(); If we remove the Concat, the query works; the tree that comes out of preprocessing is:
If we put the Concat, we get the following tree:
In other words, if the Concat isn't there, the Select is moved forward (pending selector), and the Where is processed correctly - we end up with a queryable Contains. When the Concat is there, no such movement occurs, and the Contains remains an enumerable Contains (instead of queryable, this is why we fail the translation). I'm not sure why we end up with an enumerable Contains when there's a set operation - @maumar any clue? Minimal runnable reproawait using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var queryable = context.objs1.Select(o => o.Ints)
.Concat(context.objs2.Select(o => o.Ints))
.Where(o => o.Contains(8))
.ToList();
public class BlogContext : DbContext
{
public DbSet<Obj1> objs1 { get; set; }
public DbSet<Obj2> objs2 { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("Host=localhost;Username=test;Password=test")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
public class Obj1
{
public string Id { get; set; }
public int[] Ints { get; set; }
}
public class Obj2
{
public string Id { get; set; }
public int[] Ints { get; set; }
} |
@elad-legit as a side comment - we use upvotes to gauge how many of our users actually run into an issue, and having lots of people around you voting for it creates a false image of that (it seems that all 20 votes above come from your company). Can you please refrain from doing that? |
Yes, sorry about that. Unfortunately, our actual use case is much more complicated, and we can't easily move the where before the Concat. |
@maumar Is there any timeline we should expect regarding this issue? |
@elad-legit @yair-legit Sorry for late replay. We are absolutely swamped with investigations regular dev work and other stuff, so response times are way longer than usual. var queryable = context.objs1.Select(_ => new { _.Id, _.Types }).Where(_ => _.Types.Contains(SomeEnum.E1))
.Concat(context.objs2.Select(_ => new { _.Id, _.Types }).Where(_ => _.Types.Contains(SomeEnum.E1)))
//.Where(_ => _.Types.Contains(SomeEnum.E1))
.ToList(); this produces the following sql: SELECT [o].[Id], [o].[Types]
FROM [objs1] AS [o]
WHERE 0 IN (
SELECT [t].[value]
FROM OPENJSON([o].[Types]) WITH ([value] int '$') AS [t]
)
UNION ALL
SELECT [o0].[Id], [o0].[Types]
FROM [objs2] AS [o0]
WHERE 0 IN (
SELECT [t0].[value]
FROM OPENJSON([o0].[Types]) WITH ([value] int '$') AS [t0]
) which is not ideal, but should unblock the scenarios. |
Problem is in nav expansion. For the case without Concat, when processing source of Where method, we break that part down to QueryRootExpression (objs) and pending selector of member access to Ints primitive collection. Then, during In the Concat case, nav expansion is not smart enough to extract pending selector (we couldn't do it even if we knew how - can't Concat two different sources, so the projections need to stay inside concat). We end up with source being QueryRoot.Select(x => x.Ints).Concat(...) and the pending selector is just identity projection. Then, Ultimately it's a pending selector issue (#32957) |
Description
After upgrading to EF8 from EF6, one of our complex queries including array operations stopped working ( everything worked fine with EF6 ).
After debugging, we narrowed the problem to array operation after using union or concat. ( writing the same query without using concat worked fine )
Entity Framework Query
Stack traces
EF Core version: 8.0.2
Database provider: Npgsql 8.0.2
Target framework: .NET 8.0
The text was updated successfully, but these errors were encountered: