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
Configuration¶
Basic Setup¶
Basic Setup
.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., AppServiceDbContext → appservice-db). Override the name explicitly with WithEFCore<MyDbContext>("my-database").
With Connection Retry¶
Two retry layers exist depending on the driver:
- EF Core driver (turnkey) — the generated
UseNpgsqlregistration enablesEnableRetryOnFailure(maxRetryCount: 3, maxRetryDelay: 5s)for transient command failures. - Dapper driver —
AddWhizbangPostgres(...)waits for the database at startup usingPostgresConnectionRetrywith exponential backoff, configured viaPostgresOptions:
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
};
}
}
Vector Search¶
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; } = "";
}