Fix on-the-fly event store schema + InitialData seeding on startup (#219) - #233
Merged
jeremydmiller merged 1 commit intoJun 25, 2026
Merged
Conversation
…DatabaseChangesOnStartup (#219) Two gaps the reporter hit, both about Polecat not evaluating schema on first use the way Marten does: 1. Event store not created on the fly. Document tables are ensured on first Store/query (DocumentTableEnsurer), but the event store tables (pc_streams / pc_events / pc_event_progression, plus tag and natural-key tables) were only created by ApplyAllDatabaseChangesOnStartup. A first append or event query on a fresh database failed with "Invalid object name 'pc_streams'/'pc_events'". Added DocumentTableEnsurer.EnsureEventStoreSchemaAsync (idempotent, once per process) and call it from the append path (DocumentSessionBase.SaveChanges, before the data transaction, when there are events) and the event read path (QueryEventStore's leaf helpers via QuerySession). 2. InitialData never ran without ApplyAllDatabaseChangesOnStartup. The PolecatActivator that runs IInitialData seeders was only registered by ApplyAllDatabaseChangesOnStartup / AddAsyncDaemon / AddProjectionCoordinator, so the documented `options.InitialData.Add(...)` pattern silently did nothing. AddPolecat now registers the activator unconditionally (StartAsync is a no-op when there's no InitialData and ShouldApplyChangesOnStartup is false), so seeders run on host startup as documented. Also honor AutoCreate.None: both the document and the new event on-the-fly paths now skip implicit creation when the user opts out with AutoCreate.None (previously the document ensurer ignored it and always created on the fly). Tests: appending/querying events on a fresh DB creates the event store; AutoCreate.None skips it; and IInitialData runs on host startup via AddPolecat alone (mirroring marcominerva's query-then-seed seeder). Verified on SQL Server 2025 and 2022; broad Seeding/Events/Storage/Documents/Projections/ MultiTenancy/Diagnostics suites green (~600 tests). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jeremydmiller
deleted the
fix/219-on-the-fly-event-store-and-initial-data
branch
June 25, 2026 22:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #219.
Analysis: two gaps, both "Polecat doesn't evaluate schema on first use like Marten does"
The reporter found that
IInitialDataseeding only ran whenApplyAllDatabaseChangesOnStartupwas called. Digging in (per the maintainer's framing — on-the-fly migration for the first usage of a document type or the IEvent) surfaced two distinct gaps:1. The event store is not created on the fly ❌ → ✅
Document tables ARE ensured on first
Store/query (DocumentTableEnsurer), and document queries ensure too — but the event store tables (pc_streams/pc_events/pc_event_progression, plus tag and natural-key tables) were only ever created byApplyAllDatabaseChangesOnStartup. A first append or event query on a fresh DB failed:(Confirmed with a failing repro before the fix.)
Fix: added
DocumentTableEnsurer.EnsureEventStoreSchemaAsync(idempotent, once per process, applies theEventStoreFeatureSchema) and call it from:DocumentSessionBase.SaveChanges, before the data transaction, only when there are events to write (it opens its own connection, like the document ensure);QueryEventStore's leaf helpers (FetchStream/Load/FetchStreamState; the aggregate helpers delegate through these), via a newQuerySession.EnsureEventStoreSchemaAsync.2. InitialData never ran without
ApplyAllDatabaseChangesOnStartup❌ → ✅The
PolecatActivatorhosted service that runsIInitialData.Populatewas only registered byApplyAllDatabaseChangesOnStartup/AddAsyncDaemon/AddProjectionCoordinator. So the documented pattern —— silently did nothing (the reporter's exact symptom). Fix:
AddPolecatnow registers the activator unconditionally. ItsStartAsyncis a no-op when there's noInitialDataandShouldApplyChangesOnStartupis false, so it's safe for every app. The seeder writes through normal sessions, so the document tables it touches are still created on the fly.Also: honor
AutoCreate.NoneThe maintainer's principle was "on the fly unless
AutoCreate.None." The document ensurer actually ignoredAutoCreate.Noneand always created tables. Both the document and the new event on-the-fly paths now skip implicit creation underAutoCreate.None, so the manual-schema opt-out works as intended.Tests
on_the_fly_event_store_tests— appending and querying events on a fresh DB now create the event store;AutoCreate.Nonecorrectly skips (append throws).initial_data_host_startup_tests— builds a real service provider withAddPolecat(... InitialData.Add ...)and noApplyAllDatabaseChangesOnStartup, starts the hosted services, and confirms the seeder ran — using marcominerva's query-then-seed shape (which also exercises on-the-fly document creation from inside the seeder).Verified on SQL Server 2025 and 2022; broad Seeding/Events/Storage/Documents/Projections/MultiTenancy/Diagnostics suites green (~600 tests, including all existing
AutoCreate.Nonetests).🤖 Generated with Claude Code