Changelog
What changed in Socigy.OpenSource.DB. The `[Index]` attribute (single-column and composite, unique, partial, covering, sorted, with portable index methods and scaffolding support), plus migration rollback fixes (a DOWN script dropped an auto-increment sequence before the table depending on it, and the first migration dropped the history table it had to record the rollback in) in 0.3.7; NativeAOT support (string-named projection / `keep` overloads and a reflection-based predicate folder replacing `Expression.Compile`, so the library and a consuming app publish with `PublishAot`), plus Vault/OpenBao encryption fixes — per-column profiles activate, `UseSocigyVaultEncryption()` primes before migrations, and background rotation no longer overflows its timer — in 0.3.6; a single `InsertFields` enum (plus a `keep` selector) replacing the per-call insert booleans on the context, static, and bulk paths, plus fixes making migration apply idempotent across app restarts and safe across concurrent replicas, cancellation-token support on the generated query and write APIs, and a binary-COPY UTC-timestamp fix, in 0.3.5; modular-monolith and multi-project fixes (`required` members, flowing Npgsql/Bcl dependencies, a `contextName` for lowercase databases, and per-call `[Default]` control on every insert path) in 0.3.4; Binary COPY bulk insert, scalar/affected/DTO procedure returns, database-first scaffolding, and Transit data-key envelope encryption with per-column profiles and OpenBao support in 0.3.3; runtime-named typed tables ([TableType] and DynamicTable) in 0.3.2; the database-context bulk insert plus scalar and aggregate API in 0.3.1; and 0.3.0's field encryption, rotating credentials, and HashiCorp Vault package.
- `[Index]` declares a database index. Put it on a property for a single-column index, or on the class listing the properties for a composite one, the same way
[Unique]works. It may be applied more than once, so a column can carry a plain index and a partial one at the same time. Options:Unique,Method,Where(partial),Include(covering), and sort order viaDescending/Nullsfor the whole index orDescendingColumns/NullsFirstColumns/NullsLastColumnsper column. Names are derived from the table and key columns (IX_,UX_when unique) unlessNameis set, with an option-derived suffix so two indexes over the same columns cannot collide, and are shortened deterministically rather than being silently truncated by the server at its identifier limit. Indexes take part in migrations like any other schema element: created with a new table, dropped and recreated when redefined, and reverted by the DOWN script. - Portable index methods.
Methodtakes aDbIndexMethodsconstant naming what the index is *for* (Default,Hash,FullText,Spatial,Contains,BlockRange) rather than one database's access method, so a model stays portable; PostgreSQL maps them tobtree,hash,gin,gist,gin, andbrin.Whereand theRawMethodescape hatch are passed to the database verbatim and tie the model to one engine. When an engine cannot express an option, one that only affects performance (method, covering columns, sort order, a filter on a non-unique index) is dropped with a warning, while one that changes what the database enforces (uniqueness, or a filter on a unique index) is reported as an error instead of being silently weakened. - Scaffolding recovers indexes.
scaffoldreads existing indexes out of the database and emits[Index]attributes for them, so scaffolding a database and generating a migration no longer produces a migration dropping the indexes it already has. Access methods come back as portable constants where one fits. Indexes backing a primary key orUNIQUEconstraint are skipped (they are already recovered as constraints), and expression indexes, which have no attribute form, are reported and left out rather than mis-read. - `SCGDB026`. An
[Index]naming a property the table does not have is now a build error.nameofgets the same check from the compiler; this covers string literals, where a typo previously surfaced only when the generated migration failed to apply.
- Rolling back a migration no longer fails on an auto-increment sequence. The DOWN script dropped a new table's sequence *before* the table itself. An
[AutoIncrement]column is created withDEFAULT nextval('<sequence>'), so the table depends on the sequence andDROP TABLE ... CASCADEdoes not cover it; PostgreSQL rejected the rollback withcannot drop sequence … because other objects depend on it. Every migration creating a table with an[AutoIncrement]column was affected, not only the first. The DOWN now drops the table first and its sequence after. - The first migration's rollback no longer drops the migration history table.
_scg_migrationswas generated into the DOWN script like any other table, but the migration runner writes the rollback bookkeeping row into it inside the *same transaction* as that script, so dropping it made the row impossible to write and rolling back the first migration could never succeed. The history table and its sequence are now excluded from every DOWN script, the same way Entity Framework Core keeps__EFMigrationsHistory. A full rollback ends with an empty user schema and an intact history table whose last row records the rollback. Because that table survives, the first migration creates it withCREATE TABLE IF NOT EXISTS, so rolling back and then forward again re-applies cleanly instead of failing with42P07: relation "_scg_migrations" already exists. - Dropping a table drops the sequence it owned. The sequence was previously left behind, so a later migration re-creating a table of the same name silently reused it and continued its old numbering instead of starting from 1. It is dropped after the table, and only when no other table still references it: a sequence named explicitly with
[AutoIncrement(SequenceName = "…")]and shared between tables is left in place, with a warning naming the sequence and the table still using it. - Rolling back a dropped table re-creates its sequence. The DOWN re-created the table with
DEFAULT nextval(…)but never re-created the sequence, so the rollback only worked while the sequence happened to still exist. It is now re-created before the table. Note that these are generation-time fixes: migration files produced by an earlier version keep the SQL they were generated with, so an existing first migration stays un-rollbackable until it is regenerated.