Linger.DataAccess
2.0.0-preview.1
dotnet add package Linger.DataAccess --version 2.0.0-preview.1
NuGet\Install-Package Linger.DataAccess -Version 2.0.0-preview.1
<PackageReference Include="Linger.DataAccess" Version="2.0.0-preview.1" />
<PackageVersion Include="Linger.DataAccess" Version="2.0.0-preview.1" />
<PackageReference Include="Linger.DataAccess" />
paket add Linger.DataAccess --version 2.0.0-preview.1
#r "nuget: Linger.DataAccess, 2.0.0-preview.1"
#:package Linger.DataAccess@2.0.0-preview.1
#addin nuget:?package=Linger.DataAccess&version=2.0.0-preview.1&prerelease
#tool nuget:?package=Linger.DataAccess&version=2.0.0-preview.1&prerelease
Linger.DataAccess
Provider-neutral ADO.NET execution, connection/transaction lifetime management, and common query semantics.
Target frameworks
- .NET 10
- .NET 9
- .NET 8
- .NET Framework 4.7.2
BeginTransAsync, CommitAsync, RollbackAsync, and ExecuteTransactionAsync are available on .NET 8 and later.
Use their synchronous counterparts on .NET Framework 4.7.2 instead of wrapping synchronous transactions as asynchronous work.
Architecture
BaseDatabase: commands, connections, transactions, cancellation, and parameter ownership.Database: datasets, tables, entity/list mapping, counts, batch queries, and parameterized batch transactions.- Provider helpers: only provider-specific capabilities.
Database accepts a standard DbProviderFactory; there is no custom provider abstraction.
using Linger.DataAccess;
using Microsoft.Data.SqlClient;
using var database = new Database(SqlClientFactory.Instance, connectionString);
Queries
DataSet allResults = database.Query("SELECT * FROM Users; SELECT * FROM Roles");
DataTable users = database.QueryTable(
"SELECT * FROM Users WHERE Active = @active",
new SqlParameter("@active", true));
List<User> mapped = database.FindListBySql<User>("SELECT Id, Name FROM Users");
List<User> asyncMapped = await database.FindListBySqlAsync(
"SELECT Id, Name FROM Users",
record => new User(record.GetInt32(0), record.GetString(1)),
cancellationToken: cancellationToken);
using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
using SqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT Name FROM Users WHERE Active = @active";
command.Parameters.Add(new SqlParameter("@active", true));
using SqlDataReader reader = await command.ExecuteReaderAsync(cancellationToken);
var streamedNames = new List<string>();
while (await reader.ReadAsync(cancellationToken))
{
streamedNames.Add(reader.GetString(0));
}
DataSet and DataTable materialization is intentionally synchronous because the BCL fill APIs are synchronous.
For asynchronous materialization, use FindListBySqlAsync. For streaming, use the provider's native ADO.NET API so
the connection, command, and reader all have explicit caller-owned lifetimes. Linger.DataAccess does not expose an
API that creates hidden command and connection resources while returning only a raw DbDataReader.
Existence and counts
bool hasRow = database.HasRows(
"SELECT 1 FROM Users WHERE Email = @email",
new SqlParameter("@email", email));
int count = await database.FindCountBySqlAsync(
"SELECT COUNT(*) FROM Users WHERE Active = @active",
[new SqlParameter("@active", true)],
cancellationToken);
Use HasRows for row existence and FindCountBySql when the numeric count is needed.
Parameterized batch transactions
var statements = new[]
{
new SqlStatement("UPDATE Accounts SET Balance = Balance - @amount WHERE Id = @id",
new SqlParameter("@amount", 100), new SqlParameter("@id", 1)),
new SqlStatement("UPDATE Accounts SET Balance = Balance + @amount WHERE Id = @id",
new SqlParameter("@amount", 100), new SqlParameter("@id", 2)),
};
int[] affected = await database.ExecuteTransactionAsync(statements, cancellationToken);
ExecuteTransactionAsync is available on .NET 8 and later. Use ExecuteTransaction on .NET Framework 4.7.2.
The transaction is committed only when every statement succeeds. Failure rolls back and rethrows the original
error. Do not call this API while an ambient transaction started by BeginTrans is active.
Large IN queries
DataTable result = database.QueryInBatches(
"SELECT * FROM Orders WHERE OrderId IN ({0})",
orderIds,
batchSize: 500);
Values are parameterized and split into batches. The first batch defines the returned DataTable schema.
Use this API only for row queries whose batch results can be concatenated directly. It does not preserve global
ordering, paging, aggregation, or distinct semantics.
Optional capabilities
Provider-specific features are exposed as capability interfaces. SQL Server implements IBulkInsert:
if (database is IBulkInsert bulkInsert)
{
await bulkInsert.BulkInsertAsync(table, "dbo.Users", cancellationToken: cancellationToken);
}
| 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 is compatible. 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. |
| .NET Framework | net472 is compatible. net48 was computed. net481 was computed. |
-
.NETFramework 4.7.2
- Linger.Utils (>= 2.0.0-preview.1)
-
net10.0
- Linger.Utils (>= 2.0.0-preview.1)
-
net8.0
- Linger.Utils (>= 2.0.0-preview.1)
-
net9.0
- Linger.Utils (>= 2.0.0-preview.1)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Linger.DataAccess:
| Package | Downloads |
|---|---|
|
Linger.DataAccess.SqlServer
Package Description |
|
|
Linger.DataAccess.Sqlite
Package Description |
|
|
Linger.DataAccess.Oracle
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-preview.1 | 38 | 8/29/2026 |
| 1.6.4 | 151 | 8/16/2026 |
| 1.6.3 | 137 | 8/5/2026 |
| 1.6.2 | 169 | 8/2/2026 |
| 1.6.0 | 162 | 7/25/2026 |
| 1.5.5 | 163 | 7/23/2026 |
| 1.5.4-preview | 148 | 7/21/2026 |
| 1.5.3-preview | 147 | 7/20/2026 |
| 1.5.2-preview | 155 | 7/19/2026 |
| 1.5.1-preview | 152 | 7/15/2026 |
| 1.5.0-preview | 149 | 7/14/2026 |
| 1.4.4-preview | 163 | 6/16/2026 |
| 1.4.3-preview | 155 | 6/15/2026 |
| 1.4.2 | 168 | 5/20/2026 |
| 1.4.1-preview | 163 | 5/12/2026 |
| 1.4.0 | 164 | 5/6/2026 |
| 1.3.3-preview | 158 | 5/5/2026 |
| 1.3.2-preview | 144 | 4/29/2026 |
| 1.3.1-preview | 156 | 4/28/2026 |
| 1.3.0-preview | 150 | 4/27/2026 |