Linger.DataAccess 2.0.0-preview.1

This is a prerelease version of Linger.DataAccess.
dotnet add package Linger.DataAccess --version 2.0.0-preview.1
                    
NuGet\Install-Package Linger.DataAccess -Version 2.0.0-preview.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Linger.DataAccess" Version="2.0.0-preview.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Linger.DataAccess" Version="2.0.0-preview.1" />
                    
Directory.Packages.props
<PackageReference Include="Linger.DataAccess" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Linger.DataAccess --version 2.0.0-preview.1
                    
#r "nuget: Linger.DataAccess, 2.0.0-preview.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Linger.DataAccess@2.0.0-preview.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Linger.DataAccess&version=2.0.0-preview.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Linger.DataAccess&version=2.0.0-preview.1&prerelease
                    
Install as a Cake Tool

Linger.DataAccess

Migration guide for 2.0

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed