Skip to content

PostgreSQL Data Provider

Verified by tests

PostgresConnectionRetryTests, PostgresDriverExtensionsTests, EFCoreExtensionsTests — library CI run #31657041675 (2026-08-13)

The PostgreSQL data provider enables Whizbang applications to use PostgreSQL as their primary data store, supporting event sourcing, perspectives, and advanced features like JSON columns and vector search.

Overview

Whizbang provides first-class PostgreSQL support through:

  • EF Core Integration - Full Entity Framework Core support with optimized configurations
  • Dapper Integration - High-performance raw SQL queries
  • Connection Pooling - Efficient connection management via Npgsql
  • JSON/JSONB Support - Native PostgreSQL JSON column types
  • Vector Search - pgvector integration for AI/ML workloads
  • UUIDv7 Support - Time-ordered UUIDs for optimal indexing

Installation

Installation

dotnet add package Whizbang.Data.EFCore.Postgres

Configuration

Basic Setup

Basic Setup

services.AddWhizbang()
    .WithEFCore<MyDbContext>()
    .WithDriver.Postgres;

.WithDriver.Postgres is a property, not a method — the connection string is resolved from configuration, not passed inline.

Connection String

The connection string is read from IConfiguration under ConnectionStrings:{name}, where the name is derived from the DbContext class name by convention (e.g., AppServiceDbContextappservice-db). Override the name explicitly with WithEFCore<MyDbContext>("my-database").

Host=localhost;Port=5432;Database=myapp;Username=postgres;Password=secret

With Connection Retry

Two retry layers exist depending on the driver:

  • EF Core driver (turnkey) — the generated UseNpgsql registration enables EnableRetryOnFailure(maxRetryCount: 3, maxRetryDelay: 5s) for transient command failures.
  • Dapper driverAddWhizbangPostgres(...) waits for the database at startup using PostgresConnectionRetry with exponential backoff, configured via PostgresOptions:

With Connection Retry

services.AddWhizbangPostgres(
    connectionString,
    jsonOptions,
    initializeSchema: true,
    perspectiveEntries,
    configureOptions: options => {
        options.InitialRetryAttempts = 5;
        options.InitialRetryDelay = TimeSpan.FromSeconds(1);
        options.MaxRetryDelay = TimeSpan.FromSeconds(120);
        options.BackoffMultiplier = 2.0;
        options.RetryIndefinitely = true;
    });
Property Default Description
InitialRetryAttempts 5 Initial retry attempts with warning logs
InitialRetryDelay 1 second Delay before first retry
MaxRetryDelay 120 seconds Maximum delay (caps exponential backoff)
BackoffMultiplier 2.0 Multiplier for exponential backoff
RetryIndefinitely true Continue retrying after initial attempts
CommandTimeoutSeconds 5 Command timeout for coordinator SQL calls
MaxInFlightCommands 50 Cap on concurrent work-coordinator calls per process

Schema Readiness

With the EF Core turnkey driver, schema initialization runs as a hosted service (WhizbangDatabaseInitializerService) during host startup. Workers await ISchemaReadyGate before issuing any SQL:

  • On successful migration, the gate is marked ready and workers proceed
  • On migration failure, the gate is never marked ready — startup throws and the host aborts rather than running on a broken schema

Features

Event Store

PostgreSQL is the recommended backend for the Whizbang event store:

Event Store

// Events stored in optimized JSONB columns
await eventStore.AppendAsync(streamId, new OrderCreatedEvent(...));

Perspectives

Perspectives are stored as PostgreSQL tables (wh_per_*) with automatic schema generation. Each table has the fixed PerspectiveRow<TModel> shape (id, data JSONB, metadata JSONB, scope JSONB, created_at, updated_at, version), plus optional physical columns:

Perspectives

// Storage mode is configured on the MODEL via [PerspectiveStorage]
[PerspectiveStorage(FieldStorageMode.Extracted)]
public record OrderSummaryDto {
    public Guid OrderId { get; init; }
    public string CustomerName { get; init; } = "";

    [PhysicalField(Indexed = true)]
    public decimal Total { get; init; }
}

// The perspective applies events to the model via pure functions
public class OrderSummaryPerspective : IPerspectiveFor<OrderSummaryDto, OrderCreatedEvent> {
    public OrderSummaryDto Apply(OrderSummaryDto currentData, OrderCreatedEvent @event) {
        return new OrderSummaryDto {
            OrderId = @event.OrderId,
            CustomerName = @event.CustomerName,
            Total = @event.Total
        };
    }
}

pgvector support is turnkey — marking any perspective model property with [VectorField] causes the generated registration to call UseVector() on the Npgsql data source and create the vector extension automatically:

Vector Search

[PerspectiveStorage(FieldStorageMode.Split)]
public record ProductSearchDto {
    [VectorField(1536)]
    public float[]? Embedding { get; init; }  // Stored as VECTOR(1536)
    public string Name { get; init; } = "";
}