Skip to content

Entity equality contains now fails with ParameterizedCollectionMode.Parameter #36311

@roji

Description

@roji

Since #36157, test NorthwindWhereQueryTestBase.Where_navigation_contains now fails when the default parameterized collection mode is set to ParameterizedCollectionMode.Parameter. The problem is that we have a special additional path creating InExpression with a value parameter, specifically for the case where Contains is invoked over the entity itself ("entity equality/containment"). The InExpression gets to SqlNullabilityProcessor, and then an UnreachableException gets thrown.

Ideally we'd remove this special path and deal with entity containment, but this presented some challenges back when I was re-implementing Contains so I left it out.

Note that before #36157 things were already hacky: because of the special path, we were expanding the value parameter to constants rather than using OPENJSON like everywhere else (see this baseline change). So I think it's OK if we continue to hack this a bit, and simply handle ParameterizedCollectionMode.Parameter in SqlNullabilityProcessor as if it's multiple parameters/constants.

Standalone repro
await using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

List<BlogDetails> details = [new BlogDetails { Id = 1 }, new BlogDetails { Id = 2 }];
_ = await context.Blogs.Where(b => details.Contains(b.Details)).ToListAsync();

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false",
                o => o.UseParameterizedCollectionMode(ParameterizedCollectionMode.Parameter))
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
}

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public BlogDetails Details { get; set; }
}

public class BlogDetails
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Metadata

Metadata

Assignees

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions