Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,16 @@ See the [mapping and migration guide](docs/migration-guide-12.1-to-13.md#explici

### SQLite reconstruction and data types

Read migration-local DTOs with `Database.Select<ScreenDto>("Common_Screens",
x => !x.Archive && x.Id > minimumId)`. This returns a materialized list, quotes
identifiers, parameterizes values and uses the active migration transaction.
See [DTO queries](docs/dto-queries.md) for column mapping, supported predicates
and SQL null semantics.
Predicates also support literal string `Contains`, `StartsWith` and `EndsWith`.
Typed `Update<T>(table, changes, predicate)` updates only properties assigned in
a DTO initializer; `Delete<T>(table, predicate)` removes matching rows. Both
require predicates, retain the migration transaction and return affected counts.

Supported rebuilds retain mapped data, named/composite keys, declared column collations, supported indexes and triggers, and the AUTOINCREMENT high-water mark. Generated columns, `STRICT`, `WITHOUT ROWID` and indexes with explicit collations are rejected for reconstruction; hidden rowid values are not preserved. Foreign keys retain separate update/delete actions; unsupported `MATCH FULL`/`PARTIAL` requests fail explicitly. See the [SQLite preservation matrix](docs/migration-framework-comparison.md#what-survives-reconstructionand-what-is-not-guaranteed).

CLR `Guid` defaults use the same blob representation as inserted GUID parameters. Existing text GUID defaults remain unchanged during unrelated rebuilds; converting mixed storage requires an explicit data migration. SQLite's `AsciiIgnoreCase` preset selects ASCII-only `NOCASE`; Unicode case-insensitive requests need a suitable custom collation, registered on the connection and selected by name.
Expand Down
49 changes: 49 additions & 0 deletions docs/_src/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,55 @@ def page(group, slug, title, summary, *sections, source="src/Migrator/Framework/
section("Database storage differs", '<p>SQLite does not enforce declared string lengths or decimal precision. UInt64 values above Int64.MaxValue are rejected there. Oracle character empty strings become NULL; Informix and Sybase have their own trimming and range behavior. Consult the <a href="https://github.com/dotnetprojects/Migrator.NET/blob/master/docs/data-type-boundary-tests.md">type support and boundary matrix</a> for supported mappings and live-test scope. A shared DbType does not imply identical native storage.</p>'))

page("Operations", "data", "Data operations", "Insert, update and delete using explicit column/value arrays. Keep predicates separate from changed values.",
section("Read DTOs", '<p>Select&lt;T&gt;(table, predicate) reads a single table into a materialized IReadOnlyList&lt;T&gt;, binds predicate values as native driver parameters and disposes the command and reader. DTOs need a public parameterless constructor and public readable/writable scalar properties. ColumnAttribute can override names; NotMappedAttribute excludes properties. Keep DTOs with their migration.</p><p>Predicates support direct comparisons, boolean composition, null checks and literal string Contains/StartsWith/EndsWith searches. Update&lt;T&gt; changes only initializer-assigned properties; Delete&lt;T&gt; removes matching rows. Both mutations require a predicate and return affected row counts. Other methods, joins and general LINQ operations fail explicitly. Comparisons follow database collation and SQL null semantics: Optional != 7 excludes NULL rows. Context.Select executes immediately during fluent authoring and cannot see queued operations. See the <a href="https://github.com/dotnetprojects/Migrator.NET/blob/master/docs/dto-queries.md">DTO query reference</a> for mapping and translation limits.</p>', pair("Read screens using a typed predicate", '''
public class ReadScreens : Migration
{
public sealed class ScreenDto
{
public int Id { get; set; }
public bool Archive { get; set; }
public string GenericDefinition { get; set; }
}
public override void Up()
{
var minimumId = 10;
var screens = Database.Select<ScreenDto>(
"Common_Screens", x => !x.Archive && x.Id > minimumId);
var matching = Database.Select<ScreenDto>("Common_Screens",
x => (!x.Archive && x.Id > 4) || x.GenericDefinition.Contains("aa"));
int updated = Database.Update<ScreenDto>("Common_Screens",
x => new ScreenDto { Archive = true },
x => x.GenericDefinition.StartsWith("old"));
int deleted = Database.Delete<ScreenDto>("Common_Screens",
x => x.Archive && x.GenericDefinition.EndsWith(".obsolete"));
}
public override void Down() { }
}
''', '''
public class ReadScreens : FluentMigration
{
public sealed class ScreenDto
{
public int Id { get; set; }
public bool Archive { get; set; }
public string GenericDefinition { get; set; }
}
public override void BuildUp(MigrationBuilder migration)
{
var minimumId = 10;
var screens = Context.Select<ScreenDto>(
"Common_Screens", x => !x.Archive && x.Id > minimumId);
var matching = Context.Select<ScreenDto>("Common_Screens",
x => (!x.Archive && x.Id > 4) || x.GenericDefinition.Contains("aa"));
int updated = Context.Update<ScreenDto>("Common_Screens",
x => new ScreenDto { Archive = true },
x => x.GenericDefinition.StartsWith("old"));
int deleted = Context.Delete<ScreenDto>("Common_Screens",
x => x.Archive && x.GenericDefinition.EndsWith(".obsolete"));
}
public override void BuildDown(MigrationBuilder migration) { }
}
''', kind="class")),
section("Insert rows", '<p>Column and value arrays must have the same length. The provider binds values using its driver-specific parameter mappings. For multiple rows issue multiple Insert.IntoTable(...).Row(...) expressions. Each Row completes one insert; its returned builder offers only IfNotExists, so a second Row cannot silently replace the first. Insert, update and delete each expose only their supported steps.</p>', pair("Insert a user", '''
Database.Insert("Users", new[] { "Id", "Name" }, new object[] { 1, "Ada" });
''', '''
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/search-index.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading