DbConnectionPlus 4.0.0
dotnet add package DbConnectionPlus --version 4.0.0
NuGet\Install-Package DbConnectionPlus -Version 4.0.0
<PackageReference Include="DbConnectionPlus" Version="4.0.0" />
<PackageVersion Include="DbConnectionPlus" Version="4.0.0" />
<PackageReference Include="DbConnectionPlus" />
paket add DbConnectionPlus --version 4.0.0
#r "nuget: DbConnectionPlus, 4.0.0"
#:package DbConnectionPlus@4.0.0
#addin nuget:?package=DbConnectionPlus&version=4.0.0
#tool nuget:?package=DbConnectionPlus&version=4.0.0
DbConnectionPlus
A lightweight .NET ORM and extension library for DbConnection that adds high-performance, type-safe helpers to reduce boilerplate code.
Write SQL as an interpolated string, get parameters and entity mapping for free:
using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions;
var lowStockProducts = connection.Query<Product>(
$"SELECT * FROM Product WHERE UnitsInStock < {Parameter(threshold)}"
);
- Parameters via interpolated strings —
{Parameter(value)}becomes a realDbParameter, so there is no SQL injection surface and noAddWithValueboilerplate. - On-the-fly temporary tables — pass an
IEnumerable<T>straight into a statement with{TemporaryTable(values)}, populated by the provider's bulk-copy API where one exists. - Entity mapping —
Query<T>,InsertEntity,UpdateEntities,DeleteEntityand their bulk and…Asynccounterparts, with optimistic concurrency support. - Native AOT and trimming ready — no companion package, no source generator, nothing to opt into, and no
IL2xxx/IL3xxxwarnings in your publish. - Minimal overhead — close to hand-written ADO.NET, and minimal allocations.
Why not just use Dapper?
This library follows the same philosophy as Dapper: extension methods on DbConnection, your own SQL, no change tracking and no LINQ provider, but with the following differences and additions:
- Querying, CRUD and AOT support in one package. For dapper you need Dapper, Dapper.Contrib and Dapper.AOT.
- Pass parameters directly inside interpolated strings. SQL injection safe.
- Pass collections as on-the-fly temporary tables directly inside interpolated strings. Also SQL injection safe.
- Optimistic concurrency out-of-the-box.
- Full native AOT compatibility (including support for ValueTuples, which Dapper.AOT lacks).
- Customizable Enum serialization (string/integer).
- Great performance.
Your values stay inside your query
// Dapper
connection.Query<Product>(
"SELECT * FROM Product WHERE SupplierId = @SupplierId AND UnitsInStock < @Threshold",
new { SupplierId = supplierId, Threshold = threshold }
);
// DbConnectionPlus
connection.Query<Product>(
$"SELECT * FROM Product WHERE SupplierId = {Parameter(supplierId)} AND UnitsInStock < {Parameter(threshold)}"
);
- No anonymous object to keep in sync with the SQL
- No renamed variable that compiles and then fails at run time
- Full auto-complete
- Full compiler verification
Throw a whole collection at the database
connection.Query<Product>(
$"SELECT * FROM Product WHERE SupplierId IN (SELECT Value FROM {TemporaryTable(retiredSupplierIds)})"
);
A temporary table is created, your collection is bulk-loaded into it (SqlBulkCopy and the equivalent elsewhere)
and it is dropped afterwards. Objects work too, so you can JOIN against in-memory data. Dapper expands
IN @ids into one parameter per element instead - a new query plan per list length, and a hard stop at the
provider's parameter limit.
Full optimistic concurrence support
connection.InsertEntity(newProduct); // database-generated values come back filled in
connection.UpdateEntity(product); // throws if someone else changed the row first
connection.DeleteEntities(discontinuedProducts);
One entity or a sequence, sync or …Async - and all of it supports optimistic concurrency: mark a property
[Timestamp] or [ConcurrencyCheck] and a stale write raises DbUpdateConcurrencyException instead of quietly
matching no rows. Composite keys included. Dapper has no CRUD at all; Dapper.Contrib adds some, but its UPDATE
matches on the key alone - so there is no optimistic concurrency anywhere in the Dapper family - and it has no
composite keys, no Oracle support and no release since 2020.
Native AOT support with no extra steps
<PublishAot>true</PublishAot>
That is the whole setup - no companion package, no source generator, no attributes, no IL2xxx / IL3xxx
warnings. Entities, records, value tuples, temporary tables, CRUD and enums all keep working. Dapper needs the
separate Dapper.AOT package plus a [DapperAot] opt-in per method, still has no value-tuple support and no
Dapper.Contrib support, and silently leaves call sites it cannot generate as ordinary Dapper - so the build
passes and the failure appears in your published binary.
Plus the data annotations you already use ([Table], [Column], [Key], [NotMapped], … - or a fluent API),
one-line enum serialization as strings or integers, untyped rows through row["Name"] rather than dynamic, and
a single hook to log or tweak every command before it runs.
Dapper is still the better pick for multi-mapping and QueryMultiple, custom ITypeHandler conversions, .NET
Framework / .NET Standard 2.0, and databases without an adapter here. The
full comparison, with benchmark
numbers, is in the repository README.
Installation
Install the core package plus the adapter for the database you use:
dotnet add package DbConnectionPlus
dotnet add package DbConnectionPlus.DatabaseAdapters.SqlServer
| Database | Adapter package | Provider |
|---|---|---|
| SQL Server | DbConnectionPlus.DatabaseAdapters.SqlServer |
Microsoft.Data.SqlClient |
| MySQL | DbConnectionPlus.DatabaseAdapters.MySql |
MySqlConnector |
| PostgreSQL | DbConnectionPlus.DatabaseAdapters.PostgreSql |
Npgsql |
| SQLite | DbConnectionPlus.DatabaseAdapters.Sqlite |
Microsoft.Data.Sqlite |
| Oracle | DbConnectionPlus.DatabaseAdapters.Oracle |
Oracle.ManagedDataAccess.Core |
Any other database system can be supported by implementing a custom adapter.
Getting started
Register the adapter(s) once at application startup:
using RentADeveloper.DbConnectionPlus.Configuration;
DbConnectionExtensions.Configure(config => config.UseSqlServer());
Then use the extension methods on any DbConnection:
using static RentADeveloper.DbConnectionPlus.DbConnectionExtensions;
// Query entities, scalars and value tuples
var product = connection.QuerySingle<Product>($"SELECT * FROM Product WHERE Id = {Parameter(id)}");
var count = connection.ExecuteScalar<Int32>($"SELECT COUNT(*) FROM Product");
var (id, name) = connection.QueryFirst<(Int64 Id, String Name)>($"SELECT Id, Name FROM Product");
// Rows without a type - read columns with the indexer or via dynamic member access
var row = connection.QueryFirst($"SELECT * FROM Product WHERE Id = {Parameter(id)}");
var unitsInStock = row["UnitsInStock"];
dynamic row = connection.QueryFirst($"SELECT * FROM Product WHERE Id = {Parameter(id)}");
var unitsInStock = row.UnitsInStock;
// CRUD
connection.InsertEntity(product);
connection.UpdateEntities(products);
connection.DeleteEntity(product);
// A collection as a temporary table, joined in SQL
var retired = connection.Query<Product>(
$"""
SELECT *
FROM Product
WHERE SupplierId IN (SELECT Value FROM {TemporaryTable(retiredSupplierIds)})
"""
);
Every method has an …Async counterpart, and all of them accept an optional transaction, command timeout,
command type and cancellation token.
Native AOT
Reference the packages and publish — there is nothing to install and nothing to opt into. Publishing with
PublishAot or PublishTrimmed reports no IL2xxx or IL3xxx diagnostic for any supported scenario, on
net8.0 and net10.0 alike.
The one API that cannot work under Native AOT is dynamic member access on a row (row.Id), because the
Dynamic Language Runtime needs run-time code generation; use the row["Id"] indexer instead. End-to-end
support is also bounded by your ADO.NET provider — see the AOT section of the full documentation for the
per-provider matrix.
Documentation
Licensed under the MIT license.
| 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
- Humanizer.Core (>= 3.0.10)
- LinkDotNet.StringBuilder (>= 3.4.2)
-
net8.0
- Humanizer.Core (>= 3.0.10)
- LinkDotNet.StringBuilder (>= 3.4.2)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on DbConnectionPlus:
| Package | Downloads |
|---|---|
|
DbConnectionPlus.DatabaseAdapters.Oracle
Oracle database adapter for DbConnectionPlus. |
|
|
DbConnectionPlus.DatabaseAdapters.SqlServer
SQL Server database adapter for DbConnectionPlus. |
|
|
DbConnectionPlus.DatabaseAdapters.Sqlite
SQLite database adapter for DbConnectionPlus. |
|
|
DbConnectionPlus.DatabaseAdapters.MySql
MySQL database adapter for DbConnectionPlus. |
|
|
DbConnectionPlus.DatabaseAdapters.PostgreSql
PostgreSQL database adapter for DbConnectionPlus. |
GitHub repositories
This package is not used by any popular GitHub repositories.
See CHANGELOG.md.