Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 58 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# StrEnum.Dapper

Allows to use [StrEnum](https://github.com/StrEnum/StrEnum/) string enums with Dapper.
Lets you use [StrEnum](https://github.com/StrEnum/StrEnum/) string enums with Dapper.

Supports Dapper v2.0.4+
Supports Dapper 2.0.4+.

## Installation

You can install [StrEnum.Dapper](https://www.nuget.org/packages/StrEnum.Dapper/) using the .NET CLI:
Install [StrEnum.Dapper](https://www.nuget.org/packages/StrEnum.Dapper/) via the .NET CLI:

```
dotnet add package StrEnum.Dapper
```

## Usage

Define a string enum and an entity that uses it:
### Defining a string enum and an entity

```csharp
public class Sport: StringEnum<Sport>
Expand All @@ -34,13 +34,13 @@ public class Race

### Initialization

Invoke the `StrEnumDapper.UseStringEnums` method before the first use of Dapper:
Call `StrEnumDapper.UseStringEnums()` before the first use of Dapper:

```csharp
StrEnumDapper.UseStringEnums();
```

Note, that the `UseStringEnums` method searches for string enums in all the _loaded_ assemblies, and then registers them with Dapper. Since .NET loads assemblies in a lazy fashion, make sure that the assemblies containing string enums are loaded before calling `UseStringEnums`. You can do that either implicitly, by referencing types in such assemblies, or by explicitly loading such assemblies. For example, if `Sport` is located in a separate assembly, you can load it the following way:
`UseStringEnums()` searches all *loaded* assemblies for string enums and registers each with Dapper. Since .NET loads assemblies lazily, make sure the assemblies containing your string enums are loaded before this call — either implicitly, by referencing a type from them, or explicitly:

```csharp
Assembly.Load(typeof(Sport).Assembly.GetName());
Expand All @@ -52,51 +52,75 @@ Assembly.Load(typeof(Sport).Assembly.GetName());
connection.Execute(@"INSERT Races(Id, Name, Sport) values (@id, @name, @sport)",
new[]
{
new
{
id = Guid.NewGuid(),
name = "Chornohora Sky Marathon",
sport = Sport.TrailRunning
},
new
{
id = Guid.NewGuid(),
name = "Cape Town Cycle Tour",
sport = Sport.RoadCycling
},
new
{
id = Guid.NewGuid(),
name = "Cape Epic",
sport = Sport.MountainBiking
}
new { id = Guid.NewGuid(), name = "Chornohora Sky Marathon", sport = Sport.TrailRunning },
new { id = Guid.NewGuid(), name = "Cape Town Cycle Tour", sport = Sport.RoadCycling },
new { id = Guid.NewGuid(), name = "Cape Epic", sport = Sport.MountainBiking }
});
```

### Running queries

You can pass string enums in query parameters and map them to your entities:
Pass string enums as query parameters and map them onto your entities:

```csharp
var trailRuns = connection.Query(@"SELECT Id, Name, Sport FROM Races WHERE Sport = @sport", new { sport = Sport.TrailRunning });
var trailRuns = connection.Query(
@"SELECT Id, Name, Sport FROM Races WHERE Sport = @sport",
new { sport = Sport.TrailRunning });
```

Note, that you cannot use string enums in the `IN` clause - Dapper [does not support](https://github.com/DapperLib/Dapper/issues/1134) it yet. The following won't work:
Dapper [doesn't yet support](https://github.com/DapperLib/Dapper/issues/1134) string enums in `IN` clauses, so this won't work:

```csharp
var cyclingRaces = connection.Query(@"SELECT Id, Name, Sport FROM Races WHERE Sport in @sports",
new { sports = new[]{ Sport.TrailRunning, Sport.MountainBiking }});
var cyclingRaces = connection.Query(
@"SELECT Id, Name, Sport FROM Races WHERE Sport in @sports",
new { sports = new[] { Sport.TrailRunning, Sport.MountainBiking } });
```

The workaround would be to case each of the string enum's members to string:
Cast each member to `string` as a workaround:

```csharp
var cyclingRaces = connection.Query(@"SELECT Id, Name, Sport FROM Races WHERE Sport in @sports",
new { sports = new[]{ (string)Sport.TrailRunning, (string)Sport.MountainBiking }});
var cyclingRaces = connection.Query(
@"SELECT Id, Name, Sport FROM Races WHERE Sport in @sports",
new { sports = new[] { (string)Sport.TrailRunning, (string)Sport.MountainBiking } });
```

## Postgres native enum columns

`StrEnum.Dapper` flattens `StringEnum<T>` to its underlying `string` value at the Dapper layer, which Postgres accepts straight into a `text` column. Native Postgres enum columns (`CREATE TYPE ... AS ENUM`) are a different story: Postgres has no implicit cast from `text` to a user-defined enum, so you'll see:

```
42804: column "sport" is of type sport but expression is of type text
```

`StrEnum.Dapper` does not currently bind the parameter to the enum's OID for you. Two practical workarounds:

* **Cast in SQL:** add `::your_enum` to the parameter site. Works against existing tables without ceremony.

```csharp
connection.Execute(
"INSERT INTO races (id, name, sport) VALUES (@id, @name, @sport::sport)",
new { id = Guid.NewGuid(), name = "Chornohora Sky Marathon", sport = Sport.TrailRunning });
```

* **Bypass the Dapper handler for that parameter** with a hand-rolled `NpgsqlParameter` that sets `DataTypeName`:

```csharp
var p = new DynamicParameters();
p.Add("id", Guid.NewGuid());
p.Add("name", "Chornohora Sky Marathon");
p.Add(new NpgsqlParameter
{
ParameterName = "sport",
DataTypeName = "sport",
Value = (string)Sport.TrailRunning,
});
connection.Execute("INSERT INTO races (id, name, sport) VALUES (@id, @name, @sport)", p);
```

If you only need raw Npgsql wire support (no Dapper), use [StrEnum.Npgsql](https://github.com/StrEnum/StrEnum.Npgsql/) — `NpgsqlDataSourceBuilder.MapStringEnum<T>()` binds `Sport` instances directly to the enum OID. There's no first-class `StrEnum.Npgsql.Dapper` package today; if you'd find one useful, please open an issue.

## License

Copyright &copy; 2022 [Dmitry Khmara](https://dmitrykhmara.com).
Copyright &copy; 2026 [Dmytro Khmara](https://dmytrokhmara.com).

StrEnum is licensed under the [MIT license](LICENSE.txt).
StrEnum is licensed under the [MIT license](LICENSE.txt).
Loading