StringThing.Npgsql 2.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package StringThing.Npgsql --version 2.0.0
                    
NuGet\Install-Package StringThing.Npgsql -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StringThing.Npgsql" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StringThing.Npgsql" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="StringThing.Npgsql" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StringThing.Npgsql --version 2.0.0
                    
#r "nuget: StringThing.Npgsql, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StringThing.Npgsql@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StringThing.Npgsql&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=StringThing.Npgsql&version=2.0.0
                    
Install as a Cake Tool

StringThing.Npgsql

Injection-safe interpolated SQL for PostgreSQL, built on Npgsql. Part of StringThing.

Install

dotnet add package StringThing.Npgsql

Quick start

var userId = 42;
PostgresSql stmt = $"SELECT name FROM users WHERE id = {userId}";
await using var command = stmt.ToCommand(dataSource);

Result mapping

Mark row types with [StringThingRow] and declare them partial. A source generator emits an AOT-friendly row materializer — no reflection, no IL emit, no third-party mapper.

using StringThing.Aot;

[StringThingRow]
public partial record User(int Id, string Name, string? Email);

await using var connection = await dataSource.OpenConnectionAsync();

var user = await connection.QueryStringSingleAsync<User>(
    $"SELECT id AS \"Id\", name AS \"Name\", email AS \"Email\" FROM users WHERE id = {userId}");

var users = await connection.QueryStringAsync<User>(
    $"SELECT id AS \"Id\", name AS \"Name\", email AS \"Email\" FROM users ORDER BY id");

await connection.ExecuteStringAsync($"DELETE FROM users WHERE id = {userId}");

The full surface: QueryString<T>, QueryStringFirst<T>, QueryStringFirstOrDefault<T>, QueryStringSingle<T>, QueryStringSingleOrDefault<T>, ExecuteString, ExecuteStringScalar (+ T overload), plus Async variants. Column ordinals are resolved once per query; rows are then read by ordinal — name-based binding without per-row name lookup.

Override the column name with [Column] from System.ComponentModel.DataAnnotations.Schema:

[StringThingRow]
public partial record User(
    [property: Column("user_id")] int Id,
    [property: Column("full_name")] string Name);

Nullable annotations drive IsDBNull checks — string? becomes a null-checked read; string is a direct read.

If the generator can't handle your shape — say, you want to derive a property from a column rather than read it straight, or read columns into a shape the generator couldn't infer from the type — implement IStringThingRow<T> by hand. Same runtime path:

public sealed class UserSummary : IStringThingRow<UserSummary>
{
    public int Id { get; init; }
    public string Status { get; init; } = "";

    public static ReadOnlySpan<string> ColumnBindingOrder => ["id", "email"];

    public static UserSummary Read(DbDataReader reader, ReadOnlySpan<int> ordinals) => new()
    {
        Id = reader.GetInt32(ordinals[0]),
        Status = reader.IsDBNull(ordinals[1]) ? "no-email" : "has-email",
    };
}

Supported types

All standard .NET types (int, string, DateTime, Guid, etc.) plus Postgres-specific types: NpgsqlPoint, NpgsqlBox, NpgsqlRange<T>, NpgsqlTsVector, NpgsqlTsQuery, IPAddress, and more. See PostgresValue for the full list.

Nullable variants are supported. Reference types (string?, byte[]?, IPAddress?) map to NULL. Value types use PostgresValue?.

Fragments

var minAge = 18;
var status = "active";
PostgresFragment filter = $"age >= {minAge} AND status = {status}";

PostgresSql stmt = $"SELECT * FROM users WHERE {filter}";

Fragments compose. Parameters renumber automatically across fragment boundaries.

Multi-row insert

record InsertUser(int Id, string Name, string? Email) : IPostgresRow
{
    public PostgresFragment RowValues => $"({Id}, {Name}, {Email})";
}

var users = new InsertUser[] { new(1, "alice", "alice@example.com"), new(2, "bob", null) };
PostgresSql stmt = $"INSERT INTO users (id, name, email) VALUES {PostgresSql.InsertRows(users)}";

JSON

Implement IPostgresJson on your types to store them as jsonb. Use your choice of serializer:

record UserData(string Name, int Age) : IPostgresJson
{
    public string ToJson() => $$"""{"name":"{{Name}}","age":{{Age}}}""";
}

PostgresSql stmt = $"INSERT INTO data (payload) VALUES ({userData})";

Unsafe escape hatch

var tableName = Sql.Unsafe("users");
PostgresSql stmt = $"SELECT * FROM {tableName} WHERE id = {userId}";

Built by Immersus Machina

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on StringThing.Npgsql:

Package Downloads
StringThing.Npgsql.Dapper

Dapper result mapping for StringThing.Npgsql. Injection-safe interpolated SQL on input, Dapper mapping on output. Dapper is bundled internally.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.2 78 5/31/2026
2.0.1 94 5/16/2026
2.0.0 93 5/15/2026
1.0.0 104 5/15/2026
0.1.2 110 4/12/2026
0.1.1 101 4/12/2026
0.1.0 106 4/12/2026