NuExt.System.Data.SQLite
0.8.6
Prefix Reserved
dotnet add package NuExt.System.Data.SQLite --version 0.8.6
NuGet\Install-Package NuExt.System.Data.SQLite -Version 0.8.6
<PackageReference Include="NuExt.System.Data.SQLite" Version="0.8.6" />
<PackageVersion Include="NuExt.System.Data.SQLite" Version="0.8.6" />
<PackageReference Include="NuExt.System.Data.SQLite" />
paket add NuExt.System.Data.SQLite --version 0.8.6
#r "nuget: NuExt.System.Data.SQLite, 0.8.6"
#:package NuExt.System.Data.SQLite@0.8.6
#addin nuget:?package=NuExt.System.Data.SQLite&version=0.8.6
#tool nuget:?package=NuExt.System.Data.SQLite&version=0.8.6
NuExt.System.Data.SQLite
NuExt.System.Data.SQLite is a high-performance ADO.NET infrastructure layer for SQLite-based .NET desktop, hybrid, and modular applications. It extends System.Data.SQLite with process-local connection synchronization, explicit transaction and database context management, lightweight DAL infrastructure, and transactional migrations with validated history tracking.
Features
- Synchronized Database Access: Coordinates operations through reentrant process-local locks, including shared locks for multiple connections targeting the same database.
- Transaction Scope Management: Provides explicit transaction state tracking, prevents nested transactions, preserves original exceptions when rollback fails, and supports coordinated execution through reentrant connection locks.
- Database Context Management: Manages connection state, transaction lifetime, commit, rollback, and deterministic resource cleanup.
- ADO.NET Utilities: Provides helpers for commands, parameters, readers, data adapters, schema inspection, and common SQLite operations.
- Allocation-Conscious APIs: Uses span-based parameters,
ValueTask-based coordination, pooling, and explicit callback state in performance-sensitive paths. - Database Migrations: Applies schema and data migrations transactionally, supports independent scopes and cross-scope dependencies, records the resulting application order, and strictly validates each migration sequence.
Why NuExt.System.Data.SQLite?
NuExt.System.Data.SQLite is intended for applications that use SQLite directly through ADO.NET and need a lightweight DAL foundation, predictable transaction ownership, synchronized multi-step operations, and forward-only schema evolution without adopting an ORM.
The library keeps SQL and ADO.NET primitives visible while centralizing repetitive infrastructure. Applications retain direct control over commands, parameters, readers, resource lifetimes, and transaction boundaries, while DAL components share a consistent execution model for standalone operations and coordinated units of work.
Database migrations follow the same ownership, locking, and transaction rules as application data access. Independent modules can evolve their schemas separately and declare dependencies without being forced into a single global migration sequence. Strict history validation prevents incompatible migration sequences from being applied silently.
By preserving SQLite's synchronous execution model and avoiding hidden change tracking, implicit query generation, and artificial asynchronous wrappers, the library keeps execution predictable, makes performance costs visible, and allows database behavior to be understood directly from application code.
API Overview
Data Access and Transactions
SQLiteDalBase: Base class for DAL implementations with provider-managed operations and caller-owned transactional contexts shared across multiple DAL components.SQLiteDbConnection: Provides synchronized connection access, transaction coordination, command execution, schema inspection, and common SQLite operations.SQLiteDbTransaction: Tracks transaction state and provides explicit commit and rollback operations.SQLiteDbContext: Provides a connection and transaction shared across multiple DAL components within a caller-owned or provider-managed operation.
Database Migrations
SQLiteDbMigration: Defines a forward-only schema or data migration.SQLiteDbMigrationContext: Provides command execution within a migration transaction.SQLiteDbMigrationDependency: Declares a dependency on a migration from another scope.SQLiteDbMigrationPlan: Coordinates dependent migration sequences across multiple scopes.
Concurrency and Locking
SQLite provides file-level locking and allows concurrent access through multiple connections, but application-level operations often consist of several related steps that must remain synchronized as a single scope. A transaction may include opening a connection, executing multiple commands, committing or rolling back, and restoring the original connection state. Coordinating only the individual SQL commands is not sufficient because another operation could enter between these steps.
SQLiteDbConnection addresses this by using a reentrant process-local lock around complete database operation scopes. Reentrancy allows higher-level operations, DAL components, and helper methods to call each other while participating in the same synchronized scope without deadlocking.
When shared locking is enabled, connections targeting the same database use the same process-local lock. This serializes competing operation scopes within the current process, reduces write contention, and helps prevent avoidable "database is locked" errors. When shared locking is disabled, each wrapper connection uses its own lock.
The process-local lock complements SQLite locking rather than replacing it. It cannot coordinate access from other processes or external database tools, which must still rely on SQLite file locking, busy timeouts, and an appropriate journal mode.
Transactions can be used directly when the caller guarantees exclusive connection access. Concurrent or reentrant scenarios should keep the complete transaction lifetime within AcquireLock, ExecuteInTransaction, or a provider-managed SQLiteDbContext scope.
Database Context Ownership
SQLite DAL operations support both provider-managed and caller-owned database contexts.
When no context is supplied, the provider creates the connection and context, acquires the required lock, commits the transaction on success, rolls it back on failure, and releases all owned resources.
An existing SQLiteDbContext can instead be shared across multiple DAL components. In this mode, the caller retains ownership of the transaction and decides when to commit, roll back, and dispose the context.
Quick Examples
DAL Example
internal sealed class MovieDal(Func<SQLiteDbConnection> createConnection)
: SQLiteDalBase(createConnection)
{
public ValueTask<MovieDto?> LoadMovieAsync(
SQLiteDbContext? context,
long id,
CancellationToken cancellationToken)
{
return ExecuteInDbContextAsync(context, ctx =>
{
using var command = ctx.Connection.CreateCommandSelect(
"Movies",
["Id", "Title", "Description", "DateReleased"],
"WHERE Id = @Id LIMIT 1",
DbType.Int64.CreateInputParam("@Id", id));
MovieDto? movie = null;
ctx.Connection.ExecuteReader(
command,
reader =>
{
movie = new MovieDto(
reader.GetInt64("Id"),
reader.GetString("Title"),
reader.GetNullableString("Description"),
reader.GetDateTime("DateReleased"));
},
cancellationToken: cancellationToken);
return movie;
}, cancellationToken);
}
}
Passing null as the database context creates a provider-managed operation that owns its connection, lock, transaction, and resource lifetime. Passing an existing SQLiteDbContext allows multiple DAL components to participate in the same caller-owned transaction.
Transaction Example
connection.ExecuteInTransaction(transaction =>
{
connection.ExecuteNonQuery(
"UPDATE Movies SET Title = @Title WHERE Id = @Id",
cancellationToken,
DbType.String.CreateInputParam("@Title", title),
DbType.Int64.CreateInputParam("@Id", id));
transaction.Commit();
}, cancellationToken);
The callback is responsible for committing the transaction or explicitly rolling it back when the operation completes normally. If the callback throws while the transaction is still active, the transaction is rolled back automatically without replacing the original exception with a rollback error.
Migration Example
internal sealed class CreateMoviesSchema_0001 : SQLiteDbMigration
{
public override string Id => "0001_CreateMoviesSchema";
public override void Up(SQLiteDbMigrationContext context)
{
context.ExecuteNonQuery(
"""
CREATE TABLE Movies (
Id INTEGER PRIMARY KEY,
Title TEXT NOT NULL
);
""");
}
}
SQLiteDbMigration[] migrations =
[
new CreateMoviesSchema_0001()
];
migrations.Migrate(CreateConnection, "1.0.0", cancellationToken);
Migrate applies a single ordered migration sequence within the default scope. The complete migration batch runs within a synchronized transaction and is rolled back if any migration fails.
Multiple Migration Scopes
internal sealed class CreateVideoSchema_0001 : SQLiteDbMigration
{
public override string Id => "0001_CreateVideoSchema";
public override IReadOnlyList<SQLiteDbMigrationDependency> Dependencies =>
[
new("core", "0001_CreateMoviesSchema")
];
public override void Up(SQLiteDbMigrationContext context)
{
context.ExecuteNonQuery(
"""
CREATE TABLE Videos (
Id INTEGER PRIMARY KEY,
MovieId INTEGER NOT NULL,
FileName TEXT NOT NULL
);
""");
}
}
SQLiteDbMigration[] coreMigrations =
[
new CreateMoviesSchema_0001()
];
SQLiteDbMigration[] videoModuleMigrations =
[
new CreateVideoSchema_0001()
];
var plan = new SQLiteDbMigrationPlan()
.AddScope("core", coreMigrations, "1.0.0")
.AddScope("video", videoModuleMigrations, "1.0.0");
plan.Migrate(CreateConnection, cancellationToken);
Use MigrateScope when an application component owns its own migration sequence. For example, the application core and an optional video module can evolve independently without coordinating migration identifiers or sharing one global version number.
Use SQLiteDbMigrationPlan when one component requires schema changes introduced by another. The plan determines which migration can run next, preserves the declared order within every scope, and rolls back the complete migration batch if a required migration is missing or the dependencies cannot be resolved.
The applied history of each scope must match the beginning of its configured migration sequence. This prevents an application from silently continuing when migrations have been removed, reordered, or replaced after being applied.
Optional dependencies allow a module to integrate with another module when it is installed. A dependency is ignored only when the referenced scope has never been registered or recorded, so removing a previously installed module cannot silently hide its migration history.
Applied migrations are recorded in the __nuext_migrations table together with their scope, sequence, dependencies, application time, and optional application version.
When a connection factory is used, the complete plan runs within one synchronized transaction. A plan can also use an existing SQLiteDbContext when migrations must participate in a transaction owned by the caller.
Installation
Via NuGet:
dotnet add package NuExt.System.Data.SQLite
Or via Visual Studio:
- Go to
Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution.... - Search for
NuExt.System.Data.SQLite. - Click "Install".
Compatibility
- .NET Standard 2.0+, .NET 8/9/10, and .NET Framework 4.6.2+
Usage Examples
For examples of how to use these classes, see the samples. These samples provide practical guidance on implementing the library's features in real-world scenarios.
Ecosystem
- NuExt.System
- NuExt.System.Data
- NuExt.Minimal.Mvvm
- NuExt.Minimal.Mvvm.SourceGenerator
- NuExt.Minimal.Behaviors.Wpf
- NuExt.Minimal.Mvvm.Wpf
- NuExt.Minimal.Mvvm.MahApps.Metro
Contributing
Issues and PRs are welcome. Keep changes minimal and performance-conscious.
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 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 Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 is compatible. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
.NETFramework 4.7.1
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
.NETStandard 2.0
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
.NETStandard 2.1
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
net10.0
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
net8.0
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
-
net9.0
- NuExt.System.Data (>= 0.8.5)
- System.Data.SQLite.Core (>= 1.0.119)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.8.6 | 49 | 10/23/2026 |
| 0.8.5 | 85 | 10/18/2026 |
| 0.8.4 | 87 | 10/18/2026 |
| 0.8.3 | 94 | 10/14/2026 |
| 0.8.2 | 94 | 10/13/2026 |
| 0.8.1 | 97 | 10/13/2026 |
| 0.8.0 | 93 | 10/12/2026 |
| 0.7.6 | 104 | 10/2/2026 |
| 0.7.5 | 175 | 6/30/2026 |
| 0.7.4 | 152 | 6/29/2026 |
| 0.7.3 | 170 | 3/15/2026 |
| 0.7.1 | 147 | 3/2/2026 |
| 0.7.0 | 153 | 2/12/2026 |
| 0.6.0 | 163 | 1/11/2026 |
| 0.5.2 | 346 | 12/15/2025 |
| 0.5.1 | 267 | 12/14/2025 |
| 0.4.1 | 498 | 12/10/2025 |
| 0.4.0 | 241 | 12/5/2025 |
| 0.3.3 | 291 | 2/21/2025 |
| 0.3.2 | 249 | 1/22/2025 |