/DB

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.

updated 2 Sept 202666 min readv0.3.7View as Markdown
28 July 2026
Socigy.OpenSource.DBv0.3.7stable
Added
  • `[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 via Descending / Nulls for the whole index or DescendingColumns / NullsFirstColumns / NullsLastColumns per column. Names are derived from the table and key columns (IX_, UX_ when unique) unless Name is 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. Method takes a DbIndexMethods constant 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 to btree, hash, gin, gist, gin, and brin. Where and the RawMethod escape 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. scaffold reads 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 or UNIQUE constraint 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. nameof gets the same check from the compiler; this covers string literals, where a typo previously surfaced only when the generated migration failed to apply.
Fixed
  • 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 with DEFAULT nextval('<sequence>'), so the table depends on the sequence and DROP TABLE ... CASCADE does not cover it; PostgreSQL rejected the rollback with cannot 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_migrations was 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 with CREATE TABLE IF NOT EXISTS, so rolling back and then forward again re-applies cleanly instead of failing with 42P07: 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.