Skip to content

Mapping a Postgres Enum to Multiple CLR Enums #3715

@JohnYoungers

Description

@JohnYoungers

Is there a way to map multiple c# enum definitions to the same postgres enum?

The scenario being if I have a table that's used in multiple ways, I may have facades over that table that better represent it depending on the content of the row (such as a 'type' column): per type, maybe only some of the enum values are applicable, and I'd like to reflect that in the facade with its own specific enum.

The following example results in Reading as 'TestType' is not supported for fields having DataTypeName 'public.test_type'

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

var connectionString = "Host=localhost;Username=postgres;Password=postgres_password_123;Database=test_db";
// manually run
_ = """
    CREATE TYPE public.test_type AS ENUM ('one','two','three','four','five','six');
    CREATE TABLE public."Test" ("Id" uuid NOT NULL PRIMARY KEY, "Type" public.test_type NOT NULL);
    INSERT INTO public."Test" ("Id", "Type") VALUES (gen_random_uuid(), 'one');
    """;

var services = new ServiceCollection();
services.AddPooledDbContextFactory<MyContext>(optionsBuilder =>
    optionsBuilder.UseNpgsql(connectionString, npgsql => npgsql.MapEnum<TestType>().MapEnum<FacadeType>("test_type")));

var serviceProvider = services.BuildServiceProvider();
using var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<MyContext>();

Console.WriteLine(await context.Test.FirstOrDefaultAsync());
// both of these will fail
Console.WriteLine(await context.Database.SqlQuery<TestFacade>($"""SELECT "Id", "Type" from public."Test" """).FirstOrDefaultAsync());
Console.WriteLine(await context.Test.Select(i => new TestFacade { Id = i.Id, Type = (FacadeType)(object)i.Type}).FirstOrDefaultAsync());

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

    public virtual DbSet<TestSet> Test { get; set; }
}

public class TestSet
{
    public Guid Id { get; set; }
    public TestType Type { get; set; }
}

public record TestFacade
{
    public Guid Id { get; set; }
    public FacadeType Type { get; set; }
}

public enum TestType
{
    One,
    Two,
    Three,
    Four,
    Five,
    Six
}

public enum FacadeType
{
    One,
    Two,
    Three
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions