pengdows.crud
2.0.5
dotnet add package pengdows.crud --version 2.0.5
NuGet\Install-Package pengdows.crud -Version 2.0.5
<PackageReference Include="pengdows.crud" Version="2.0.5" />
<PackageVersion Include="pengdows.crud" Version="2.0.5" />
<PackageReference Include="pengdows.crud" />
paket add pengdows.crud --version 2.0.5
#r "nuget: pengdows.crud, 2.0.5"
#:package pengdows.crud@2.0.5
#addin nuget:?package=pengdows.crud&version=2.0.5
#tool nuget:?package=pengdows.crud&version=2.0.5
pengdows.crud
pengdows.crud is a SQL-first data access library for .NET 8+. It favors explicit SQL, inspectable command builders, and provider-aware execution over ORM-style query generation.
No LINQ. No tracking. No hidden unit of work.
What The Code Exposes
DatabaseContext/IDatabaseContextfor connection lifecycle, dialect behavior, quoting, parameter creation, metrics, and transactionsTableGateway<TEntity, TRowID>/ITableGateway<TEntity, TRowID>for row-id CRUD, business-key retrieval, batch operations, and async streamingPrimaryKeyTableGateway<TEntity>/IPrimaryKeyTableGateway<TEntity>for tables keyed only by[PrimaryKey]columnsISqlContainerfor build-first SQL composition plus direct execution helpersITransactionContextfor explicit commit, rollback, and savepoint control
Main Capabilities
- Build-first CRUD:
BuildCreate,BuildRetrieve,BuildUpdateAsync,BuildDelete,BuildUpsert - Load prebuilt containers with
LoadSingleAsync,LoadListAsync, andLoadStreamAsync - Convenience methods such as
CreateAsync,RetrieveOneAsync,RetrieveAsync,UpdateAsync,DeleteAsync, andUpsertAsync - Native
DbDataSourcesupport for shared prepared-statement caching (e.g.,NpgsqlDataSource) - Batch create, update, upsert, and delete operations with parameter-limit-aware chunking
- Optimistic concurrency via
[Version] - Audit field population via
IAuditValueResolver - JSON, enum, GUID, binary, UTC date/time, and advanced provider-specific type mappings
- Metrics snapshots via
IDatabaseContext.Metricsand live updates viaMetricsUpdated DbModestrategies:Standard,KeepAlive,SingleWriter,SingleConnection, andBest- Typed exception hierarchy: provider
DbExceptionis translated to structured subtypes (ConcurrencyConflictException,UniqueConstraintViolationException,DeadlockException, etc.)
Supported Products
The repository contains concrete support for:
- SQL Server
- PostgreSQL
- Aurora PostgreSQL
- MySQL
- Aurora MySQL
- MariaDB
- Oracle
- SQLite
- Firebird
- DuckDB
- CockroachDB
- YugabyteDB
- TiDB
- Snowflake
When product detection cannot identify the connected database, the library falls back to a conservative SQL-92 dialect.
Quick Start
dotnet add package pengdows.crud
using Microsoft.Data.SqlClient;
using pengdows.crud;
var context = new DatabaseContext(
"Server=.;Database=app;Trusted_Connection=True;",
SqlClientFactory.Instance);
var gateway = new TableGateway<Order, long>(context);
bool created = await gateway.CreateAsync(new Order
{
Id = 42,
OrderNumber = "ORD-42"
});
var one = await gateway.RetrieveOneAsync(42L);
var many = await gateway.RetrieveAsync(new long[] { 42, 43 });
await using var tx = await context.BeginTransactionAsync();
await gateway.UpsertAsync(order, tx);
await tx.CommitAsync();
Constructor Variants
// Minimal: connection string + factory
var ctx = new DatabaseContext(connectionString, SqlClientFactory.Instance);
// With read-only replica
var ctx = new DatabaseContext(connectionString, SqlClientFactory.Instance,
readOnlyConnectionString: replicaConnectionString);
// Full configuration object (logger, pool sizes, prepare mode, etc.)
var ctx = new DatabaseContext(
new DatabaseContextConfiguration
{
ConnectionString = connectionString,
DbMode = DbMode.Standard,
ReadWriteMode = ReadWriteMode.ReadWrite,
ReadOnlyConnectionString = replicaConnectionString,
MaxConcurrentReads = 20,
MaxConcurrentWrites = 5
},
SqlClientFactory.Instance,
loggerFactory);
// Provider DbDataSource (PostgreSQL prepared-statement sharing)
var dataSource = NpgsqlDataSource.Create(connectionString);
var ctx = new DatabaseContext(configuration, dataSource, NpgsqlFactory.Instance);
Key Mapping Rules
[Id]is the row identifier used by row-id operations[PrimaryKey]is the business key and may be composite[Id]and[PrimaryKey]must not be placed on the same property- Use
PrimaryKeyTableGateway<TEntity>when the entity has no[Id]column at all
Exception Handling
Raw DbException from providers is automatically translated to a typed hierarchy:
DatabaseException (abstract — carries Database, SqlState, ErrorCode, ConstraintName, IsTransient)
├─ DatabaseOperationException
│ ├─ ConcurrencyConflictException ← [Version] column mismatch on UpdateAsync
│ ├─ CommandTimeoutException ← IsTransient = true
│ ├─ ConnectionException
│ ├─ TransactionException
│ ├─ TransientWriteConflictException ← IsTransient = true
│ │ ├─ DeadlockException
│ │ └─ SerializationConflictException
│ └─ ConstraintViolationException (abstract)
│ ├─ UniqueConstraintViolationException
│ ├─ ForeignKeyViolationException
│ ├─ NotNullViolationException
│ └─ CheckConstraintViolationException
├─ DataMappingException
└─ SqlGenerationException
Non-DatabaseException subtypes thrown by the infrastructure:
ModeContentionException : TimeoutException— SingleWriter/SingleConnection lock timed outPoolSaturatedException : TimeoutException— internal connection pool exhaustedPoolForbiddenException : InvalidOperationException— write attempted on read-only contextTransactionModeNotSupportedException : NotSupportedException— savepoint or read-only tx on unsupported dialectConnectionFailedException : Exception— startup connection failure (carriesPhaseandRole)
try
{
await gateway.UpdateAsync(entity);
}
catch (ConcurrencyConflictException)
{
// [Version] mismatch — reload and retry
}
catch (UniqueConstraintViolationException ex)
{
// ex.ConstraintName identifies which constraint fired
}
catch (DatabaseException ex) when (ex.IsTransient == true)
{
// Deadlock, serialization failure, or timeout — safe to retry
}
ISqlContainer Scalar Execution
Three distinct methods replace the ambiguous ExecuteScalarAsync from v1:
// Throws if no rows or value is null/DBNull and T is non-nullable
int count = await sc.ExecuteScalarRequiredAsync<int>();
// Returns null for both "no rows" and "DBNull value"
string? name = await sc.ExecuteScalarOrNullAsync<string>();
// Unambiguously distinguishes no-row, null, and value
ScalarResult<string> result = await sc.TryExecuteScalarAsync<string>();
if (result.Status == ScalarStatus.Value) { /* result.Value */ }
if (result.Status == ScalarStatus.Null) { /* row returned but value was NULL */ }
if (result.Status == ScalarStatus.None) { /* no rows returned */ }
Documentation
- Repo docs: docs/
- Wiki: https://github.com/pengdows/pengdows.crud/wiki
Support
If this library saves you time, consider buying me a coffee.
| 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 was computed. 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
- Microsoft.Extensions.Configuration.Binder (>= 9.0.6)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.6)
- pengdows.crud.abstractions (>= 2.0.5)
-
net8.0
- Microsoft.Extensions.Configuration.Binder (>= 9.0.6)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.6)
- pengdows.crud.abstractions (>= 2.0.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on pengdows.crud:
| Package | Downloads |
|---|---|
|
pengdows.hangfire
SQL-first Hangfire job storage built on pengdows.crud — a strongly-typed, cross-database data access layer for .NET. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.5 | 119 | 4/17/2026 |
| 2.0.4 | 181 | 3/31/2026 |
| 2.0.3 | 160 | 3/27/2026 |
| 2.0.2 | 103 | 3/24/2026 |
| 2.0.1 | 108 | 3/22/2026 |
| 2.0.0 | 173 | 2/28/2026 |
| 1.0.1769867481 | 167 | 1/31/2026 |
| 1.0.1769543242 | 117 | 1/27/2026 |
| 1.0.1769395132 | 117 | 1/26/2026 |
| 1.0.1769360331 | 110 | 1/25/2026 |
| 1.0.1767194225 | 137 | 12/31/2025 |
| 1.0.1759683344 | 192 | 10/5/2025 |
| 1.0.1759623120 | 183 | 10/5/2025 |
| 1.0.1756777911 | 215 | 9/2/2025 |
| 1.0.1756431873 | 239 | 8/29/2025 |
| 1.0.1756401895 | 241 | 8/28/2025 |
| 1.0.1756206653 | 269 | 8/26/2025 |
| 1.0.1756088498 | 273 | 8/25/2025 |
| 1.0.1755050805 | 207 | 8/13/2025 |
| 1.0.1754686097 | 198 | 8/8/2025 |