Nanorm 0.1.0
See the version list below for details.
dotnet add package Nanorm --version 0.1.0
NuGet\Install-Package Nanorm -Version 0.1.0
<PackageReference Include="Nanorm" Version="0.1.0" />
paket add Nanorm --version 0.1.0
#r "nuget: Nanorm, 0.1.0"
// Install Nanorm as a Cake Addin #addin nuget:?package=Nanorm&version=0.1.0 // Install Nanorm as a Cake Tool #tool nuget:?package=Nanorm&version=0.1.0
Nanorm
A tiny data-access helper library for ADO.NET. Trimming and native AOT friendly.
It supports:
- PostgreSQL via
Npgsql
- SQLite via
Microsoft.Data.SQLite
- Any ADO.NET data provider via
System.Data.Common
How to use
Nanorm supports .NET 6+, with special support for .NET 7+ thanks to static virtual members on interfaces and source generators.
Getting started
Install the
Nanorm
package that's suitable for the ADO.NET provider (i.e. database) you're using. Using thedotnet
command line in the project directory:PostgreSQL:
dotnet add package Nanorm.Npgsql --prerelease
SQLite:
dotnet add package Nanorm.Sqlite --prerelease
All other ADO.NET providers:
dotnet add package Nanorm --prerelease
Create a
class
,record
, orstruct
to map a database query result to. If you're using .NET 7 or .NET 8, you can make itpartial
and decorate it with the[DataRecordMapper]
attribute to enable the source generator which will take care of implementing theIDataRecordMapper<T>
interface for you:[DataRecordMapper] public partial class Todo { public int Id { get; set; } public required string Title { get; set; } public bool IsComplete { get; set; } } // Generated for you if .NET 7+, otherwise you'll need to write it yourself partial class Todo : IDataRecordMapper<Todo> { public static Todo Map(System.Data.IDataRecord dataRecord) => new() { Id = dataRecord.GetInt32("Id"), Title = dataRecord.GetString("Title"), IsComplete = dataRecord.GetBoolean("IsComplete"), }; }
Create an instance of the appropriate
IDbConnection
type and use one of the Nanorm extension methods to execute a query. TheQueryAsync
methods returnIAsyncEnumerable
so you canawait foreach
over the results or simply callToListAsync()
to asynchronously get aList<T>
result:// Using Npgsql to query a local PostgreSQL instance var connectionString = "Server=localhost;Port=5432;Username=postgres;Database=postgres"; await using var db = new NpgsqlDataSourceBuilder(connectionString).Build(); var todos = db.QueryAsync<Todo>("SELECT * FROM Todos"); var todosList = await todos.ToListAsync(); if (todosList.Count == 0) { Console.WriteLine("There are currently no todos!"); } else { Console.WriteLine($"Found {todosList.Count} todo(s):"); foreach (var todo in todosList) { Console.WriteLine($"({todo.Id}) {todo.Title}"); } }
Using parameters
Nanorm supports a few different ways to pass parameters to queries:
Passing an interpolated string that is processed by Nanorm's custom string interpolation handler. This is the preferred approach. The query is automatically parameterized in an optimal way, i.e. no string concatenation, uses pooled allocations, etc.:
var title = "Do the dishes"; var result = db.QueryAsync<Todo>($"SELECT * FROM Todos WHERE Title = {title}")
Passing instances of the ADO.NET provider's
DbParameter
implementation as parameters, e.g.:var title = "Do the dishes"; var sql = "SELECT * FROM Todos WHERE Title = $1"; var result = db.QueryAsync<Todo>(sql, new NpgsqlParameter { Value = title }))
Passing a callback that modifies the ADO.NET provider's parameter collection implementation, e.g.:
var title = "Do the dishes"; var sql = "SELECT * FROM Todos WHERE Title = $1"; var result = db.QueryAsync<Todo>(sql, parameters => parameters.Add(title))
Extension methods
The following extension methods are provided to make it easier to work against your database:
Method | Description |
---|---|
ExecuteAsync |
Executes a command that does not return any results. |
ExecuteScalarAsync |
Executes a command and returns the first column of the first row in the first returned result set. All other columns, rows, and result sets are ignored. |
QueryAsync |
Executes a command and returns the result as an appropriately typed DbDataReader |
QueryAsync<T> |
Executes a command and returns the rows mapped to instances of T as an IAsyncEnumerable<T> |
QuerySingleAsync<T> |
Executes a command and maps the first row returned to an instance of T |
AsDbParameter |
Creates a provider-specific parameter object from the object value |
AsTypedDbParameter<T> |
Creates a generic parameter from the T value (Npgsql only) |
ToListAsync<T> |
Asynchronously converts an IAsyncEnumerable<T> to a List<T> |
Benchmarks
Nanorm is intended to be a very thin layer over ADO.NET with support for trimming and native AOT. Here's how it compares to raw ADO.NET and Dapper for a simple insert & return operation with regards to execution time and memory allocations:
Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|
AdoNet | 443.5 us | 12.67 us | 37.17 us | 432.9 us | 1.00 | 0.00 | 3.28 KB | 1.00 |
AdoNetDbCommon | 443.1 us | 8.75 us | 21.63 us | 437.7 us | 1.00 | 0.10 | 4.97 KB | 1.51 |
Dapper | 424.3 us | 10.70 us | 30.86 us | 415.0 us | 0.96 | 0.11 | 3.51 KB | 1.07 |
DapperAot | 403.6 us | 7.92 us | 12.56 us | 402.5 us | 0.91 | 0.07 | 3.54 KB | 1.08 |
NanormDbParameters | 404.9 us | 7.87 us | 10.51 us | 402.3 us | 0.91 | 0.07 | 3.44 KB | 1.05 |
NanormStringInterpolation | 412.8 us | 8.07 us | 14.77 us | 408.6 us | 0.93 | 0.08 | 3.46 KB | 1.05 |
NanormDbCommonParameters | 417.6 us | 8.32 us | 16.62 us | 415.0 us | 0.94 | 0.09 | 3.63 KB | 1.11 |
NanormDbCommonStringInterpolation | 414.7 us | 8.20 us | 15.99 us | 410.1 us | 0.94 | 0.08 | 3.9 KB | 1.19 |
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Nanorm:
Package | Downloads |
---|---|
Nanorm.Npgsql
Package Description |
|
Nanorm.Sqlite
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.