StrEnum.Npgsql.EntityFrameworkCore
1.0.1
Prefix Reserved
See the version list below for details.
dotnet add package StrEnum.Npgsql.EntityFrameworkCore --version 1.0.1
NuGet\Install-Package StrEnum.Npgsql.EntityFrameworkCore -Version 1.0.1
<PackageReference Include="StrEnum.Npgsql.EntityFrameworkCore" Version="1.0.1" />
<PackageVersion Include="StrEnum.Npgsql.EntityFrameworkCore" Version="1.0.1" />
<PackageReference Include="StrEnum.Npgsql.EntityFrameworkCore" />
paket add StrEnum.Npgsql.EntityFrameworkCore --version 1.0.1
#r "nuget: StrEnum.Npgsql.EntityFrameworkCore, 1.0.1"
#:package StrEnum.Npgsql.EntityFrameworkCore@1.0.1
#addin nuget:?package=StrEnum.Npgsql.EntityFrameworkCore&version=1.0.1
#tool nuget:?package=StrEnum.Npgsql.EntityFrameworkCore&version=1.0.1
StrEnum.Npgsql.EntityFrameworkCore
Entity Framework Core integration for StrEnum.Npgsql — maps StrEnum string enums to native Postgres enum types in EF Core models, migrations, and queries.
This is the EF wrapper, mirroring how the Npgsql ecosystem ships Npgsql.NetTopologySuite (raw driver) and Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite (EF wrapper) as separate packages. If you only need the ADO.NET driver path, use StrEnum.Npgsql directly.
Supports EF Core 8 – 10. Targets net8.0, net9.0, net10.0.
Installation
Install StrEnum.Npgsql.EntityFrameworkCore via the .NET CLI:
dotnet add package StrEnum.Npgsql.EntityFrameworkCore
(StrEnum.Npgsql is brought in transitively.)
Usage
StrEnum.Npgsql.EntityFrameworkCore lets you choose how Entity Framework stores your string enums in Postgres:
- as plain text columns (the default), or
- as native Postgres enum types created via
CREATE TYPE ... AS ENUM (...).
Storing string enums as text
Defining a string enum and an entity
public class Sport: StringEnum<Sport>
{
public static readonly Sport RoadCycling = Define("ROAD_CYCLING");
public static readonly Sport MountainBiking = Define("MTB");
public static readonly Sport TrailRunning = Define("TRAIL_RUNNING");
}
public class Race
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public Sport Sport { get; private set; }
private Race() { }
public Race(string name, Sport sport)
{
Id = Guid.NewGuid();
Name = name;
Sport = sport;
}
}
Wiring it up
Call UseStringEnums() when configuring your DB context:
public class RaceContext: DbContext
{
public DbSet<Race> Races { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseNpgsql("Host=localhost;Database=BestRaces;Username=*;Password=*;")
.UseStringEnums();
}
}
EF Core stores the Sport property in a text column. Running dotnet ef migrations add Init produces:
migrationBuilder.CreateTable(
name: "Races",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Sport = table.Column<string>(type: "text", nullable: false)
},
constraints: table => table.PrimaryKey("PK_Races", x => x.Id));
Storing string enums as Postgres enum types
Three things have to line up for parameters to bind cleanly to a native Postgres enum:
- The enum type must exist in the database (
CREATE TYPE ... AS ENUM). - Npgsql has to know the CLR type ↔ enum OID mapping at the wire.
- EF Core has to pick a
RelationalTypeMappingthat doesn't pin the parameter totext.
StrEnum.Npgsql.EntityFrameworkCore covers all three:
// 1. Wire-level binding (StrEnum.Npgsql)
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
dataSourceBuilder.MapStringEnum<Sport>();
await using var dataSource = dataSourceBuilder.Build();
// 2. EF Core hookup
public class RaceContext: DbContext
{
public RaceContext(NpgsqlDataSource dataSource) { _dataSource = dataSource; }
private readonly NpgsqlDataSource _dataSource;
public DbSet<Race> Races { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseNpgsql(_dataSource)
.UseStringEnums() // string enums recognised as scalars
.UseStringEnumsAsPostgresEnums(); // route mapped properties to the enum OID
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Race>();
// 3. Migrations + per-property column type
modelBuilder.MapStringEnumAsPostgresEnum<Sport>();
}
}
The generated migration looks like this:
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:sport", "ROAD_CYCLING,MTB,TRAIL_RUNNING");
migrationBuilder.CreateTable(
name: "Races",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Sport = table.Column<Sport>(type: "sport", nullable: false)
},
constraints: table => table.PrimaryKey("PK_Races", x => x.Id));
MapStringEnumAsPostgresEnum<TEnum>() does two things:
- Registers a Postgres enum type in the EF model — produces the
CREATE TYPEmigration. Labels are taken from the string enum's underlying values, in declaration order. - Walks all entity types and configures every property of type
TEnumto use that Postgres enum as its column type.
Customising the Postgres enum name and schema
By default the Postgres enum name is the snake_cased CLR type name (Sport → sport). Override the name and schema if you need to:
modelBuilder.MapStringEnumAsPostgresEnum<Sport>(name: "sport_kind", schema: "races");
dataSourceBuilder.MapStringEnum<Sport>(name: "sport_kind", schema: "races");
Configuring individual properties
For fine-grained control over which properties map to a Postgres enum, call HasPostgresStringEnum<TEnum>() per property:
modelBuilder.HasPostgresStringEnum<Sport>(); // creates the CREATE TYPE migration
modelBuilder.Entity<Race>()
.Property(r => r.Sport)
.HasPostgresStringEnum<Sport>();
The property-level call inherits the schema set on the model-level HasPostgresStringEnum, so you don't have to repeat it.
Mixing both modes
Both modes can coexist in the same context:
modelBuilder.MapStringEnumAsPostgresEnum<Sport>(); // Sport -> sport enum
// Country has no Postgres-enum mapping, so it stays as text
Country properties stay as text because UseStringEnums() is on the options builder.
Querying
EF Core translates LINQ operations on string enums into SQL:
var trailRuns = await context.Races
.Where(r => r.Sport == Sport.TrailRunning)
.ToArrayAsync();
When Sport is mapped to a Postgres enum, the parameter is sent and compared as that enum type — no text casts, no 42804 errors.
var cyclingSports = new[] { Sport.MountainBiking, Sport.RoadCycling };
var cyclingRaces = await context.Races
.Where(r => cyclingSports.Contains(r.Sport))
.ToArrayAsync();
Acknowledgements
The relational type-mapping plugin is modelled on EFCore.PG's own type-mapping source plugins; the wire-level work lives in StrEnum.Npgsql.
License
Copyright © 2026 Dmytro Khmara.
StrEnum is licensed under the MIT license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 10.0.0 && < 11.0.0)
- StrEnum (>= 2.0.0 && < 3.0.0)
- StrEnum.Npgsql (>= 2.0.0 && < 3.0.0)
-
net8.0
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 8.0.0 && < 9.0.0)
- StrEnum (>= 2.0.0 && < 3.0.0)
- StrEnum.Npgsql (>= 2.0.0 && < 3.0.0)
-
net9.0
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 9.0.0 && < 10.0.0)
- StrEnum (>= 2.0.0 && < 3.0.0)
- StrEnum.Npgsql (>= 2.0.0 && < 3.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.