Npgsql enum array with int conversion throws InvalidCastException on "Contains"

c# ef-core-3.1 entity-framework-core enums npgsql

Question

I'm using enum to int conversion for enum arrays in npgsql due to lack of enum altering features.

Model:

public class TestEntity
{
    public Guid Id { get; set; }
    public TestEnum[] Enums { get; set; }

    public TestEntity()
    {
        Enums = new TestEnum[0];
    }
}

public enum TestEnum
{
    NONE,
    FIRST,
    SECOND,
    THIRD
}

Context:

public class TestContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TestEntity>()
            .Property(x => x.Enums)
            .HasConversion(
                e => e.Cast<int>().ToArray(),
                e => e.Cast<TestEnum>().ToArray());
    }
}

When I'm reading or writing entities from/to db without "touching" array properties in LINQ expressions everything work perfectly - columns are of type integer[] in postgres and mapping works as should.

However, when I'm using "Contains" function on enum[] property, it throws with InvalidCastException: "Can't write CLR type Proj.TestEnum with handler type Int32Handler".

Example:

var param = TestEnum.FIRST; 

var result = context.TestEntities!
    .Where(x => x.Enums.Contains(param))
    .ToArray();

Is there something I'm missing?

1
0
12/27/2019 1:58:02 PM

Accepted Answer

This is kind of a case of this issue: using value converters blocks method translation.

This should work fine if using the Npgsql's native enum support, rather than doing value conversions. You say you don't want to do that because of the lack of enum altering features - can you be more specific? PostgreSQL does support adding and renaming enum values, and you can do that via raw SQL in your migrations.

0
12/27/2019 2:20:20 PM

Popular Answer

If I understand correctly, there are 2 solutions for it 1. You can add AsEnumerable() before where condition

var result = context.TestEntities!
    AsEnumerable().Where(x => x.Enums.Contains(param))
    .ToArray();

2. You can use operator overloading from this url



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow