Skip to content

Exception when doing a Contains query against an enum field with conversion to string #1190

@alfeg

Description

@alfeg

After upgrading to EFCore 3.1 we got an issue with filtering by multiple enums.

Repro:

Npgsql.EfCore.Repro.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
  </ItemGroup>
</Project>

Program.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.Logging;

namespace Npgsql.EfCore.Repro
{
    class Program
    {
        static async Task Main(string[] args)
        {
            NpgsqlLogManager.Provider = new ConsoleLoggingProvider(NpgsqlLogLevel.Trace, true);
            NpgsqlLogManager.IsParameterLoggingEnabled = true;

            await using var dbContext = new MyContext();
            await dbContext.Database.ExecuteSqlRawAsync(@"CREATE table if not exists entity (
	id serial NOT NULL,
	status text NOT NULL,
	CONSTRAINT entity_pk PRIMARY KEY (id)
);");

            SomeEnum[] possibleValues = { SomeEnum.One, SomeEnum.Three };

            // fails with: Npgsql.PostgresException: '42883: operator does not exist: text = integer'
            // Generated SQL: 
            // DEBUG Executing statement(s):
            // SELECT e.id, e.status
            //   FROM entity AS e
            //    WHERE COALESCE(e.status = ANY($1), FALSE)
            // Parameters:     $1: System.Int32[]
            var result = await dbContext.My.Where(e => possibleValues.Contains(e.Status)).ToListAsync();
        }
    }

    public enum SomeEnum : int
    {
        One = 1,
        Two = 2,
        Three = 3
    }

    [Table("entity")]
    public class MyEntity
    {
        [Key][Column("id")]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }

        [Column("status")]
        public SomeEnum Status { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<MyEntity> My { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
               optionsBuilder.UseNpgsql(@"Server=.");         
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MyEntity>()
                .Property(x => x.Status)
                .HasConversion(new EnumToStringConverter<SomeEnum>());
        }
    }
}

This code works fine in 3.0 netcore.

Now this line

var result = await dbContext.My.Where(e => possibleValues.Contains(e.Status)).ToListAsync();

Throws : Npgsql.PostgresException: '42883: operator does not exist: text = integer' with generated SQL:

--DEBUG Executing statement(s):
SELECT e.id, e.status
FROM entity AS e
WHERE COALESCE(e.status = ANY ($1), FALSE)
--        Parameters:     $1: System.Int32[]

P.S.: Repro is mostly copied from #1189 issue.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions