Repository navigation
Marten 9.35.0
Marten 9.35.0 — Event Model naming, store identity, and idempotent archiving.
⚠️ Behaviour changes
Three, all deliberate. None require a code change to adopt, but each changes what an existing application observes.
1. A store's derived Event Model is now named after your service, not "EventModel" (#5408).
The store-derived Event Model source fell back to the literal "EventModel" — the one default guaranteed to be wrong for every host. Wolverine names its derived model after JasperFxOptions.ServiceName, and so does Bobcat's spec assembly, so the common case (Wolverine + one Marten store) assembled two models out of the box and had to restate a name it had already declared.
The fallback is now the service name. An explicit name still wins:
services.AddMarten(opts =>
{
opts.Connection(connectionString);
opts.EventModelName = "Ledgers"; // optional; defaults to JasperFxOptions.ServiceName
});If you were relying on the model being called EventModel, set opts.EventModelName = "EventModel" explicitly.
2. The primary store's Subject now follows StoreName (#5409).
Subject was a literal marten://main that ignored StoreOptions.StoreName, while Identity had always been built from it — so naming a primary store moved one and left the other behind, and Subject is the one consumers key on. Both are now built from StoreName. Tooling that keys on store.Subject (CritterWatch's explorer reads and shard progression ids among them) will see marten://{storename} for a named store where it previously saw marten://main.
A store name is user-supplied text and a uri host is not, so names are sanitized: My Store would otherwise throw UriFormatException and a/b would silently parse its tail as a path. Ordinary names are unchanged.
3. Archiving an already-archived stream is a no-op instead of an error (#5403).
Under UseArchivedStreamPartitioning, a second archive of the same stream raised 23505 on mt_streams_archived_pkey. This also stalled async single-stream projections with IncludeArchivedEvents = true when they processed an Archived marker after an inline snapshot had already archived the stream. Repeated archiving now succeeds and does nothing.
A genuine collision is still reported: a different active stream reusing an archived stream id still fails, rather than being silently swallowed and losing its metadata.
Fixes and improvements
- #5405 / #5407 —
StoreOptions.EventModelName. A host that calledAddEventModel("Something", …)assembled two models: its own, and one the store contributed under the default name. The name is configured onStoreOptionsand read lazily when the model is assembled, soAddEventModelmay be called before or afterAddMarten. - #5409 — an ancillary store keeps a name it was given.
BuildStoreOptionsassignedStoreNameboth before and after theIConfigureMarten<T>chain, so a contribution that named the store was silently reverted to the marker type's name. - #5403 — partitioned archiving performance. Because
is_archivedis the list partition key on bothmt_streamsandmt_events, the archive function's new predicates also let PostgreSQL prune to the active partition, where the previous statements had to consider both. - JasperFx 2.69.3. Codegen output is now deterministic (#832) — an
ImHashMapkeyed byFrame, which does not overrideGetHashCode, meant statement order followed identity hash codes and varied per process. Every Event Model slice also now carries the store it came from, so two stores projecting a document of the same simple name leave a recorded disagreement rather than one silently winning (#836).
Compatibility
Binary compatible with 9.34.0. The public AddMarten / AddMartenStore<T> surface is unchanged — verified by diffing the extracted signature list against the 9.34.0 tag. New configuration is additive on StoreOptions.