Linger.DataAccess 1.4.2

dotnet add package Linger.DataAccess --version 1.4.2
                    
NuGet\Install-Package Linger.DataAccess -Version 1.4.2
                    
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="1.4.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Linger.DataAccess" Version="1.4.2" />
                    
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 1.4.2
                    
#r "nuget: Linger.DataAccess, 1.4.2"
                    
#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@1.4.2
                    
#: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=1.4.2
                    
Install as a Cake Addin
#tool nuget:?package=Linger.DataAccess&version=1.4.2
                    
Install as a Cake Tool

Linger.DataAccess

A core data access library that provides database abstraction and common database operations.

Features

  • Database Abstraction: Provider-agnostic database access
  • CRUD Operations: Complete Create, Read, Update, Delete operations
  • Async Support: Full async/await support for modern applications
  • Multiple Data Types: Support for DataTable, DataSet, Entity objects, and Hashtable
  • Transaction Support: Built-in transaction management
  • SQL Builder: Helper for dynamic SQL generation
  • Bulk Operations: Interface for high-performance bulk data insertion
  • Batch Query: Large parameter list splitting (default batchSize = 1000) with parameterized & raw variants

Supported .NET Versions

  • .NET 10.0
  • .NET 9.0
  • .NET 8.0
  • .NET Framework 4.7.2+

Installation

This library is typically not installed directly, but is automatically referenced when installing specific database implementation packages:

# For SQL Server
dotnet add package Linger.DataAccess.SqlServer

# For Oracle Database
dotnet add package Linger.DataAccess.Oracle

# For SQLite
dotnet add package Linger.DataAccess.Sqlite

Core Interfaces

IDatabase

High-frequency interface groups (most commonly used):

  • Execute commands: ExecuteBySql(...), ExecuteByProc(...)
  • Query table/dataset: Query(...), QueryTable(...), QueryAsync(...), QueryTableAsync(...)
  • List/entity mapping: FindListBySql<T>(...), FindEntityBySql<T>(...)
  • Scalar helpers: FindCountBySql(...), FindMaxBySql(...)
  • Batch query for huge IN lists: QueryInBatches(...), QueryInBatchesAsync(...)

Complete API reference (source of truth):

IProvider

Database provider abstraction for different database engines.

Basic Usage

using Linger.DataAccess;

// Execute queries
var users = database.FindListBySql<User>("SELECT * FROM Users WHERE Active = 1");
var userTable = await database.FindTableBySqlAsync("SELECT * FROM Users");

// Batch query (IDs split automatically, default batchSize 1000)
var ids = Enumerable.Range(1, 5000).Select(i => i.ToString()).ToList();
var dt = database.QueryInBatches("SELECT * FROM Users WHERE Id IN ({0})", ids);

// Custom batch size
var dt500 = database.QueryInBatches("SELECT * FROM Users WHERE Id IN ({0})", ids, 500);

// Raw version (trusted numeric IDs only)
var dtRaw = database.QueryInBatchesRaw("SELECT * FROM Users WHERE Id IN ({0})", ids, 800, quote: false);

// Async parameterized version
var dtAsync = await database.QueryInBatchesAsync("SELECT * FROM Users WHERE Id IN ({0})", ids, 750);

// Execute commands
int affected = database.ExecuteBySql("UPDATE Users SET LastLogin = GETDATE()");

// Count operations
int userCount = await database.FindCountBySqlAsync("SELECT COUNT(*) FROM Users");

Batch Query

When dealing with very large IN lists (thousands of IDs) a single SQL statement may exceed length limits or degrade performance. The batch query helpers automatically split the list and concatenate the results.

// Parameterized (safe)
var result = database.QueryInBatches(
    "SELECT * FROM Orders WHERE OrderId IN ({0})",
    orderIds); // default batchSize = 1000

// Raw (only for trusted constant values)
var resultRaw = database.QueryInBatchesRaw(
    "SELECT * FROM Orders WHERE OrderId IN ({0})",
    orderIds, 500, quote: false);

Guidelines:

  • Use {0} in sql where the batch placeholder will be injected.
  • Prefer parameterized methods for security (prevents SQL injection).
  • Raw methods are only for fully trusted data (e.g., internally generated numeric IDs).
  • Adjust batchSize to balance network round-trips and SQL size limits.

Return Type:

  • All batch methods merge rows into a single DataTable preserving schema of the first non-empty batch.

Transaction Contract

When calling low-level transaction overloads in BaseDatabase / IBaseDatabase:

  • transaction.Connection must be attached and non-null.
  • Detached/disposed transactions are rejected with ArgumentNullException.
  • The connection used by transaction overloads comes from transaction.Connection.
// Correct: transaction is attached to the same open connection
using var conn = provider.CreateConnection(connString);
conn.Open();
using var tx = conn.BeginTransaction();
_ = baseDatabase.ExecuteNonQuery(tx, CommandType.Text, "UPDATE Users SET Active = 1 WHERE Id = @Id", param);

// Invalid: detached transaction -> throws ArgumentNullException
// _ = baseDatabase.ExecuteNonQuery(detachedTx, CommandType.Text, "UPDATE ...", param);

Architecture

This library provides the foundation for database-specific implementations:

  • Linger.DataAccess.SqlServer - SQL Server implementation
  • Linger.DataAccess.Oracle - Oracle Database implementation
  • Linger.DataAccess.Sqlite - SQLite implementation

Key Components

Database Class

Base implementation of IDatabase interface providing common database operations.

BaseDatabase Class

Core database functionality including connection management and parameter handling.

SqlBuilder Class

Helper utility for building dynamic SQL queries safely.

Async/Await Best Practices

True Async Implementation ✅

All async methods in this library use true asynchronous I/O operations, not Task.Run wrappers:

// ✅ TRUE ASYNC - Releases thread during I/O
public async Task<bool> ExistsAsync(string sql, CancellationToken ct = default)
{
    var count = await FindCountBySqlAsync(sql).ConfigureAwait(false);
    return count > 0;
}

// ❌ PSEUDO-ASYNC (Not used in this library)
// Task.Run just wraps synchronous blocking code
public Task<bool> BadExistsAsync(string sql)
{
    return Task.Run(() => FindCountBySql(sql)); // Wastes thread pool threads
}

Performance Benefits

Metric Synchronous Pseudo-Async (Task.Run) True Async ✅
Thread Usage 1 thread blocked 1 thread pool thread 0 threads during I/O
Concurrency ~Thousands ~Thousands ~Tens of thousands
Memory ~1MB per thread ~1MB per thread ~Few KB per task
Scalability Limited Limited Excellent
Cancellation Not supported Only before start During I/O operation

Usage Recommendations

// ✅ DO: Use async methods for I/O operations
var users = await database.FindTableBySqlAsync("SELECT * FROM Users");
var count = await database.FindCountBySqlAsync("SELECT COUNT(*) FROM Orders");

// ✅ DO: Use ConfigureAwait(false) in library code (already done internally)
var result = await database.QueryAsync(sql).ConfigureAwait(false);

// ✅ DO: Support cancellation tokens
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var data = await database.QueryTableAsync(sql, null, cts.Token);

// ❌ DON'T: Mix sync and async (use one or the other)
var badResult = database.FindTableBySqlAsync(sql).Result; // Can deadlock!

High Concurrency Scenarios

For applications handling thousands of concurrent requests:

// ✅ Scales to tens of thousands of concurrent operations
var tasks = Enumerable.Range(1, 10000)
    .Select(id => database.FindTableBySqlAsync($"SELECT * FROM Orders WHERE Id = {id}"))
    .ToList();

var results = await Task.WhenAll(tasks); // Minimal thread usage

Best Practices

  • Use parameterized queries to prevent SQL injection
  • Use batch query helpers for large IN lists instead of manual concatenation
  • Implement proper disposal patterns with using statements
  • Use async methods for I/O intensive operations - All async methods use true async I/O
  • Always pass CancellationToken to async methods for proper cancellation support
  • Use ConfigureAwait(false) in library code (already done internally)
  • Choose appropriate database-specific implementations for optimal performance
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
1.4.2 154 5/20/2026
1.4.1-preview 150 5/12/2026
1.4.0 150 5/6/2026
1.3.3-preview 144 5/5/2026
1.3.2-preview 133 4/29/2026
1.3.1-preview 143 4/28/2026
1.3.0-preview 139 4/27/2026
1.2.0-preview 150 3/29/2026
1.1.0 162 2/4/2026
1.0.3-preview 156 1/9/2026
1.0.2-preview 164 1/8/2026
1.0.0 355 11/12/2025
1.0.0-preview2 262 11/6/2025
1.0.0-preview1 255 11/5/2025
0.9.9 248 10/16/2025
0.9.8 260 10/14/2025
0.9.7-preview 241 10/13/2025
0.9.6-preview 235 10/12/2025
0.9.5 240 9/28/2025
0.9.4-preview 256 9/25/2025
Loading failed