Model migration
At startup the engine’s ModelMigrationService (an IHostedService registered by AddGenie) scans
a models directory and applies each file in dependency order — entities → views → SQL →
navbar — via a per-type strategy. This is what populates the runtime metadata stores the API
reads from; it is separate from the EF migration that creates physical tables.
What each file type does
Section titled “What each file type does” ┌─▶ *.entity.xml ──[EntityMigrationStrategy]─────────▶ Entity store + triggersModelMigrationService ─────┼─▶ *.view.xml ────[ObjectViewMigrationStrategy]─────▶ ViewStore (ObjectView JSON) scans models directory ├─▶ *.sql ─────────[StoredProcedureMigrationStrategy]─▶ Recognized DDL executed └─▶ *.navbar.xml ──[NavbarMigrationStrategy]──────────▶ Navigation store| File | Strategy | Result |
|---|---|---|
*.entity.xml |
EntityMigrationStrategy |
Upserted into the entity store (entity metadata); the per-entity sequence/search/audit triggers are (re)created here. |
*.view.xml |
ObjectViewMigrationStrategy |
Upserted into ViewStore — the polymorphic ObjectView JSON the UI renders as grid/form/view. |
*.sql |
StoredProcedureMigrationStrategy |
Recognized DDL (CREATE [OR ALTER] PROCEDURE/FUNCTION/VIEW/TRIGGER) is executed; plain SQL is only recorded. |
*.navbar.xml |
NavbarMigrationStrategy |
Synced into the navigation store. |
Each applied file is recorded by a content hash, so an unchanged file is skipped on the next boot — only changed files re-run.
Controlling it — the Startup config section
Section titled “Controlling it — the Startup config section”Model-migration behaviour binds from the Startup section (ModelMigrationOptions), overridable
in code via ConfigureMigrations:
"Startup": { "ExecuteMigration": "Forced" }No— don’t run on startup.Yes— run, skipping files whose content hash is unchanged.Forced— re-apply every file regardless of hash.
builder.Services.AddGenie<YourContext>(genie => genie .LoadFromConfiguration(builder.Configuration) .ConfigureMigrations(m => m.ExecuteMigration = ExecuteMigration.Yes));Locating the models directory
Section titled “Locating the models directory”The service resolves the directory relative to the app base directory, probing
<appBase>/../../../../../models then <appBase>/../models. The simplest portable approach is to
copy your model files into the build output and let the engine find them there. The Inventory
sample copies ../models/** into bin/.../models with a <None … CopyToOutputDirectory="PreserveNewest">
item in its csproj:
<ItemGroup> <None Include="..\models\**\*.entity.xml;..\models\**\*.view.xml;..\models\**\*.sql;..\models\**\*.navbar.xml" Link="models\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" /></ItemGroup>Match the directory layout to your deployment.
How this relates to dotnet ef migrations
Section titled “How this relates to dotnet ef migrations”Two distinct steps run against the same database, in a fixed order at boot:
dotnet ef migrations(design-time, in the host assembly) — creates the physical tables from the source-generated EF configurations. Applied by the host, typically viacontext.Database.Migrate()on startup.- Engine SQL bootstrap (
EngineSqlBootstrapper) — deploys the engine’s shared SQL objects (sequence functions, company-scope helpers, password-encryption procs). Runs before the model migration. See Backend integration. - Model migration (
ModelMigrationService) — populates the metadata stores and creates the per-entity triggers described above.
┌──────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐│ dotnet ef migrations │ ─▶ │ EngineSqlBootstrapper │ ─▶ │ ModelMigrationService ││ physical tables │ │ shared SQL objects │ │ metadata + triggers │└──────────────────────┘ └───────────────────────┘ └───────────────────────┘So authoring a new entity is: write the *.entity.xml, dotnet ef migrations add (tables), then let
the runtime migration register its metadata + triggers on the next boot.