Skip to content

arrayColumn.Contains(element) translates into element = ANY(arrayColumn) in version 10 #3862

@sskalex

Description

@sskalex

Hello! I believe I've encountered a regression while upgrading Npgsql.EntityFrameworkCore.PostgreSQL from 9.0.4 to 10.0.2.

arrayColumn.Contains(element) used to translate into [arrayColumn @> ARRAY[element]] as stated in docs.
But now it translates into element = ANY(arrayColumn). This can be critical since element = ANY(arrayColumn) operator is not supported by GIN index. Now my query seq scans the table.

Minimal repro code
using Microsoft.EntityFrameworkCore;
using Npgsql;

var dataSource = new NpgsqlDataSourceBuilder("Host=localhost")
    .Build();

var options = new DbContextOptionsBuilder<TestContext>()
    .UseNpgsql(dataSource)
    .EnableSensitiveDataLogging()
    .Options;

await using var ctx = new TestContext(options);

var query = ctx.Items.Where(i => i.Names.Contains("Test"));

Console.WriteLine(query.ToQueryString());

public class TestContext : DbContext
{
    public TestContext(DbContextOptions<TestContext> options) : base(options)
    {
    }

    public DbSet<Item> Items => Set<Item>();
}

public class Item
{
    public int Id { get; set; }

    public string[] Names { get; set; } = Array.Empty<string>();

    public int[] Numbers { get; set; } = Array.Empty<int>();
}

This repro code produces:

SELECT i."Id", i."Names", i."Numbers"
FROM "Items" AS i
WHERE 'Test' = ANY (i."Names")

I've tested various expressions and I can't make it produce @> as it used to before. All variations produce WHERE 'Test' = ANY (i."Names"). To name a few I've tried:

  • var query = ctx.Items.Where(i => i.Names.AsEnumerable().Contains("Test"));
  • var query = ctx.Items.Where(i => i.Names.ToList().Contains("Test"));
  • var query = ctx.Items.Where(i => i.Names.Any(n => n == "test"));

With Npgsql.EntityFrameworkCore.PostgreSQL 9.0.4 all those variations translate to:

SELECT i."Id", i."Names", i."Numbers"
FROM "Items" AS i
WHERE i."Names" @> ARRAY['test']::text[]

This query is supported by GIN index and I believe it is the correct translation.

P.S. - this feels related to a C# 14 breaking change of overload resolution with span parameters. That was my original thought but adding AsEnumerable() or downgrading to C# 10 didn't help. Maybe this change somehow affected the library itself but I am probably very wrong here.

Environment

Component Version
.NET 10.0
C# 14 (also fails on 10)
Microsoft.EntityFrameworkCore 10.0.9
Npgsql.EntityFrameworkCore.PostgreSQL 10.0.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions