Skip to content

Commit 4252287

Browse files
committed
Clarify resource ownership, strengthen migration validation, and update documentation
1 parent da7fe7a commit 4252287

9 files changed

Lines changed: 195 additions & 77 deletions

‎README.md‎

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# NuExt.System.Data.SQLite
22

3-
`NuExt.System.Data.SQLite` extends `System.Data.SQLite` with process-local connection synchronization, explicit transaction and database context management, lightweight DAL infrastructure, and transactional database migrations with validated history tracking for modern .NET applications.
3+
`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.
44

55
[![NuGet](https://img.shields.io/nuget/v/NuExt.System.Data.SQLite.svg)](https://www.nuget.org/packages/NuExt.System.Data.SQLite)
66
[![Ask DeepWiki](https://img.shields.io/badge/Ask-DeepWiki-blue)](https://deepwiki.com/nu-ext/NuExt.System.Data.SQLite)
@@ -14,16 +14,34 @@
1414
- **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.
1515
- **Database Context Management**: Manages connection state, transaction lifetime, commit, rollback, and deterministic resource cleanup.
1616
- **ADO.NET Utilities**: Provides helpers for commands, parameters, readers, data adapters, schema inspection, and common SQLite operations.
17-
- **Allocation-Conscious APIs**: Provides span-based parameters, `ValueTask`-based coordination, and explicit-state callbacks that help avoid closure allocations.
18-
- **Database Migrations**: Applies schema and data migrations transactionally, supports independent scopes and cross-scope dependencies, preserves global application order, and strictly validates each migration sequence.
17+
- **Allocation-Conscious APIs**: Uses span-based parameters, `ValueTask`-based coordination, pooling, and explicit callback state in performance-sensitive paths.
18+
- **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.
1919

2020
## Why NuExt.System.Data.SQLite?
2121

22-
`NuExt.System.Data.SQLite` is designed as a performance-oriented infrastructure layer over ADO.NET rather than an ORM. It keeps SQL, commands, parameters, readers, and transactions explicit while removing repetitive connection, transaction, and resource lifecycle code. It also preserves SQLite's synchronous execution model instead of wrapping database operations in artificial asynchronous work.
22+
`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.
2323

24-
The library supports both standalone DAL operations and coordinated units of work, protects complete database operation scopes during concurrent and reentrant execution, and provides forward-only migrations with deterministic dependency ordering, independent scopes, and strict history validation.
24+
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.
2525

26-
The result is a lightweight data access foundation that adds predictable resource ownership, transaction coordination, and schema evolution without introducing change tracking, SQL generation, or a custom query language.
26+
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.
27+
28+
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.
29+
30+
## API Overview
31+
32+
### Data Access and Transactions
33+
34+
- **`SQLiteDalBase`**: Base class for DAL implementations with provider-managed operations and caller-owned transactional contexts shared across multiple DAL components.
35+
- **`SQLiteDbConnection`**: Provides synchronized connection access, transaction coordination, command execution, schema inspection, and common SQLite operations.
36+
- **`SQLiteDbTransaction`**: Tracks transaction state and provides explicit commit and rollback operations.
37+
- **`SQLiteDbContext`**: Provides a connection and transaction shared across multiple DAL components within a caller-owned or provider-managed operation.
38+
39+
### Database Migrations
40+
41+
- **`SQLiteDbMigration`**: Defines a forward-only schema or data migration.
42+
- **`SQLiteDbMigrationContext`**: Provides command execution within a migration transaction.
43+
- **`SQLiteDbMigrationDependency`**: Declares a dependency on a migration from another scope.
44+
- **`SQLiteDbMigrationPlan`**: Coordinates dependent migration sequences across multiple scopes.
2745

2846
## Concurrency and Locking
2947

@@ -47,6 +65,47 @@ An existing `SQLiteDbContext` can instead be shared across multiple DAL componen
4765

4866
## Quick Examples
4967

68+
### DAL Example
69+
70+
```csharp
71+
internal sealed class MovieDal(Func<SQLiteDbConnection> createConnection)
72+
: SQLiteDalBase(createConnection)
73+
{
74+
public ValueTask<MovieDto?> LoadMovieAsync(
75+
SQLiteDbContext? context,
76+
long id,
77+
CancellationToken cancellationToken)
78+
{
79+
return ExecuteInDbContextAsync(context, ctx =>
80+
{
81+
using var command = ctx.Connection.CreateCommandSelect(
82+
"Movies",
83+
["Id", "Title", "Description", "DateReleased"],
84+
"WHERE Id = @Id LIMIT 1",
85+
DbType.Int64.CreateInputParam("@Id", id));
86+
87+
MovieDto? movie = null;
88+
89+
ctx.Connection.ExecuteReader(
90+
command,
91+
reader =>
92+
{
93+
movie = new MovieDto(
94+
reader.GetInt64("Id"),
95+
reader.GetString("Title"),
96+
reader.GetNullableString("Description"),
97+
reader.GetDateTime("DateReleased"));
98+
},
99+
cancellationToken: cancellationToken);
100+
101+
return movie;
102+
}, cancellationToken);
103+
}
104+
}
105+
```
106+
107+
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.
108+
50109
### Transaction Example
51110

52111
```csharp
@@ -130,33 +189,22 @@ SQLiteDbMigration[] videoModuleMigrations =
130189

131190
var plan = new SQLiteDbMigrationPlan()
132191
.AddScope("core", coreMigrations, "1.0.0")
133-
.AddScope("module.video", videoModuleMigrations, "1.0.0");
192+
.AddScope("video", videoModuleMigrations, "1.0.0");
134193

135194
plan.Migrate(CreateConnection, cancellationToken);
136195
```
137196

138-
Use `MigrateScope` for an independent named migration sequence. Use `SQLiteDbMigrationPlan` only when migrations from multiple scopes depend on one another.
139-
140-
Migrations are applied in the order in which they are registered within each scope. Each migration scope maintains an independent ordered sequence, and its applied history must be an exact prefix of the configured migration sequence.
197+
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.
141198

142-
`SQLiteDbMigrationPlan` coordinates multiple scopes and automatically orders pending migrations according to their declared dependencies while preserving the configured order within each scope. The plan detects missing dependencies, unknown migrations, and dependency cycles before incompatible schema changes can be applied.
199+
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.
143200

144-
Dependencies may reference required scopes or optional scopes. An optional-scope dependency is ignored only when the scope is neither registered in the plan nor present in migration history. This prevents migrations from ignoring schema changes left by a module that was previously installed but is not currently loaded.
201+
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.
145202

146-
Applied migrations are recorded in the `__nuext_migrations` table with a global history identifier, scope-local sequence, declared dependencies, application time, and optional version information. This preserves the complete migration chronology while allowing the application core and independently installed modules to maintain separate migration chains.
203+
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.
147204

148-
When a connection factory is used, the complete migration plan is executed within a synchronized transaction and is rolled back if any migration fails. A plan can also run within an existing `SQLiteDbContext`, allowing migrations and application operations to share the same caller-owned transaction.
205+
Applied migrations are recorded in the `__nuext_migrations` table together with their scope, sequence, dependencies, application time, and optional application version.
149206

150-
## Commonly Used Types
151-
152-
- **`SQLiteDalBase`**: Base class for SQLite DAL implementations with synchronized provider-managed context execution and access to connection creation for custom scenarios.
153-
- **`SQLiteDbConnection`**: Wraps SQLite connections with process-local synchronization, transaction coordination, command execution, schema inspection, and common data access utilities.
154-
- **`SQLiteDbTransaction`**: Wraps SQLite transactions with explicit state tracking, commit and rollback operations, and transaction lifetime diagnostics.
155-
- **`SQLiteDbContext`**: Manages connection state and transaction lifetime, with optional validation that the connection lock remains held for the lifetime of the context.
156-
- **`SQLiteDbMigration`**: Base class for defining forward-only SQLite schema and data migrations within ordered, independently validated scopes.
157-
- **`SQLiteDbMigrationDependency`**: Describes a required migration from another scope, including optional-scope dependencies.
158-
- **`SQLiteDbMigrationPlan`**: Coordinates multiple migration scopes, resolves cross-scope dependencies, and applies pending migrations transactionally.
159-
- **`SQLiteDbMigrationContext`**: Provides the execution context used by SQLite migrations.
207+
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.
160208

161209
## Installation
162210

@@ -174,21 +222,21 @@ Or via Visual Studio:
174222

175223
## Compatibility
176224

177-
**.NET Standard 2.0+, .NET 8/9/10 and .NET Framework 4.6.2+**
225+
- **.NET Standard 2.0+, .NET 8/9/10, and .NET Framework 4.6.2+**
178226

179227
## Usage Examples
180228

181-
For examples of how to use these classes, see the [samples](samples). These samples provide practical guidance on implementing the library's features in real-world scenarios.
229+
For examples of how to use these classes, see the [samples](https://github.com/nu-ext/NuExt.System.Data.SQLite/tree/main/samples). These samples provide practical guidance on implementing the library's features in real-world scenarios.
182230

183231
## Ecosystem
184232

233+
- [NuExt.System](https://github.com/nu-ext/NuExt.System)
234+
- [NuExt.System.Data](https://github.com/nu-ext/NuExt.System.Data)
185235
- [NuExt.Minimal.Mvvm](https://github.com/nu-ext/NuExt.Minimal.Mvvm)
186236
- [NuExt.Minimal.Mvvm.SourceGenerator](https://github.com/nu-ext/NuExt.Minimal.Mvvm.SourceGenerator)
187237
- [NuExt.Minimal.Behaviors.Wpf](https://github.com/nu-ext/NuExt.Minimal.Behaviors.Wpf)
188238
- [NuExt.Minimal.Mvvm.Wpf](https://github.com/nu-ext/NuExt.Minimal.Mvvm.Wpf)
189239
- [NuExt.Minimal.Mvvm.MahApps.Metro](https://github.com/nu-ext/NuExt.Minimal.Mvvm.MahApps.Metro)
190-
- [NuExt.System](https://github.com/nu-ext/NuExt.System)
191-
- [NuExt.System.Data](https://github.com/nu-ext/NuExt.System.Data)
192240

193241
## Contributing
194242

‎src/NuExt.System.Data.SQLite.csproj‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>netstandard2.1;netstandard2.0;net10.0;net9.0;net8.0;net471;net462</TargetFrameworks>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7-
<Description>High-performance SQLite data access utilities for .NET, providing synchronized process-local connection access, explicit transaction management, a consistent DAL foundation, and transactional database migrations with validated history tracking.</Description>
7+
<Description>High-performance ADO.NET infrastructure for SQLite-based .NET applications, providing synchronized process-local connection access, explicit transaction and database context management, a consistent DAL foundation, and transactional migrations with validated history tracking.</Description>
88
<RootNamespace />
99
<GenerateDocumentationFile>True</GenerateDocumentationFile>
1010
<NoWarn>$(NoWarn);1591;NETSDK1233</NoWarn>
@@ -16,7 +16,7 @@
1616
</ItemGroup>
1717

1818
<ItemGroup Condition="'$(NuExt_UseLocalProjects)' != 'true'">
19-
<PackageReference Include="NuExt.System.Data" Version="0.8.4" />
19+
<PackageReference Include="NuExt.System.Data" Version="0.8.5" />
2020
</ItemGroup>
2121

2222
<ItemGroup Condition="'$(NuExt_UseLocalProjects)' == 'true'">

0 commit comments

Comments
 (0)