Skip to content

9.0: widen document Revision int → long (#3733)#4377

Merged
jeremydmiller merged 2 commits into
masterfrom
revision-long-3733
May 12, 2026
Merged

9.0: widen document Revision int → long (#3733)#4377
jeremydmiller merged 2 commits into
masterfrom
revision-long-3733

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Closes #3733.

Breaking change for Marten 9.0. The numeric revision tracking column (mt_version when UseNumericRevisions is enabled) widens from integer to bigint, and every .NET-side surface that carries a document revision moves from int to long.

Why

int capped Marten's numeric-revision tracking at ~2.1B updates per document — well within reach for high-throughput inline projections and event-sourced aggregates that snapshot per event. long removes the ceiling without changing the public surface beyond the type widening.

What changed (Marten core)

Surface Before After
Marten.Metadata.IRevisioned.Version int long
DocumentMetadata.CurrentRevision int long
IRevisionedOperation.Revision int long
IDocumentSession.UpdateRevision<T>(entity, revision) int revision long revision
IDocumentSession.TryUpdateRevision<T>(entity, revision) int revision long revision
IDocumentStorage<T>.Store(IMartenSession, T, int) int long
VersionTracker.RevisionFor / StoreRevision / RevisionsFor int long
MetadataColumn<int> for RevisionColumn <int> <long>
MartenRegistry.MetadataConfig.Revision Column<int> Column<long>
mt_doc_*.mt_version (numeric revisions) integer bigint
mt_upsert_* / mt_update_* / mt_overwrite_* revision arg + return + locals INTEGER BIGINT
Bulk-loader expected-version column / param NpgsqlDbType.Integer NpgsqlDbType.Bigint

Schema migration

Non-destructive widening from a Marten 8 deployment: RevisionColumn.AlterColumnTypeSql now emits ALTER TABLE … ALTER COLUMN mt_version TYPE bigint; when it sees an existing integer column. Existing revision values are preserved. Switching from a Guid-versioned column (uuid) to numeric revisions still drops and recreates the column as before.

Bonus

  • Fixed an NRE in MetadataColumn<T>.Member.set when the diagnostic message for a type-mismatched member ran on the first assignment (the message referenced the still-null _member field — now references the incoming value).

What user code needs to do

  • Any : IRevisioned implementation: widen the Version property to long.
  • Any [Version]-annotated numeric property used with UseNumericRevisions: widen to long.
  • Any m.Revision.MapTo(x => x.SomeProperty) configuration: the target property must be long.

This is the documented Marten 8 → 9 migration shape; the migration guide section is being tracked in #4355.

Verification

  • Full DocumentDbTests on net9.0: 968 passed, 1 skipped, 0 failed (~58s)
  • EventSourcingTests subset that touches IRevisioned (when_finding_the_last_good_aggregation, using_explicit_code_for_live_aggregation, stream_compacting, fetching_live_aggregates, fetching_inline_aggregates): 81 passed
  • PatchingTests (Bug_3261_patch_plus_revisions): 1 passed
  • CoreTests revision-related: 6 passed
  • DocumentDbTests/Concurrency/numeric_revisioning: 22 passed
  • DocumentDbTests/Writing/bulk_loading_Tests.overwrite_if_version_matches_respects_expected_revision: passed

The committed TestCodeGen-validated RevisionedDocProvider1212098993.cs was regenerated from this widening (now reads long).

Out of scope

  • JasperFx.IRevisioned (a duplicate of Marten.Metadata.IRevisioned in the JasperFx package) still has int Version. The three test classes that resolved to JasperFx's interface via using JasperFx; are now explicitly qualified to Marten.Metadata.IRevisioned. Deduplicating the two interfaces is a follow-up for the Marten 9.0 dedupe-with-JasperFx pass (umbrella [Master] Marten 9.0 #4349).
  • Migration guide language: tracked in [Docs] Marten 8 → Marten 9 migration guide #4355 as its own PR.

Test plan

  • CI green across the test matrix (net9.0 / net10.0, both serializers)
  • TestCodeGen nuke task passes (the committed regen file matches the widened codegen output)
  • Docs CI passes (docs/documents/concurrency.md int Version snippets updated)

🤖 Generated with Claude Code

#3733)

Breaking change for Marten 9.0. The numeric revision tracking column (`mt_version` when
`UseNumericRevisions` is on) is now `bigint` rather than `integer`, and all .NET-side
surfaces that carry the revision widen from `int` to `long`:

  - `Marten.Metadata.IRevisioned.Version`
  - `DocumentMetadata.CurrentRevision`
  - `IRevisionedOperation.Revision`
  - `IDocumentSession.UpdateRevision` / `TryUpdateRevision` parameter
  - `IDocumentStorage<T>.Store(IMartenSession, T, long)`
  - `VersionTracker.RevisionFor` / `StoreRevision` / `RevisionsFor`
  - `MetadataColumn<int>` → `MetadataColumn<long>` for `RevisionColumn`
  - Bulk-loader expected-version argument (`bigint`)
  - `mt_upsert_*` / `mt_update_*` / `mt_overwrite_*` function signatures and local
    variables (`final_version` / `current_version`) now `BIGINT`
  - `MartenRegistry.MetadataConfig.Revision` exposed as `Column<long>`

Schema migration from a Marten 8 deployment is non-destructive: the existing
`integer` column is widened in place via `ALTER COLUMN ... TYPE bigint`, preserving
all stored revision values. Switching from a Guid-versioned column to numeric
revisions still drops and recreates the column.

Also fixes an NRE in `MetadataColumn.Member.set` when the rejected member-type
diagnostic ran on the first (null `_member`) assignment.

User-visible code that implements `IRevisioned` or carries a `[Version]` numeric
property must widen the property to `long`. The migration guide (#4355) covers
this.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…3733 CI fix)

CI on #4377 surfaced one missed [Version]-annotated property: the test
class MyAggregateWithDifferentVersionProperty had

    [Version]
    public int SpecialVersion { get; set; }

The original sed-based widening only matched the literal
"public int Version" property name; this one slipped through because
the property is called SpecialVersion. Widened to long.

Also tightened src/Marten/Schema/VersionAttribute.cs:
  * The Modify() branch that accepted int is removed — [Version] on a
    Marten 9 numeric-revisioning property must be long, since
    MetadataColumn<long> rejects an int member at registration time.
  * A dedicated diagnostic now fires when a user annotates an int
    property, naming the declaring type/member and pointing at the
    migration-guide section so the fix is obvious from the stack trace.
  * The catch-all error message dropped "int" from the supported types
    list to match the new contract.

Verified locally:
  * The previously-failing test
    EventSourcingTests.Aggregation.setting_version_number_on_aggregate.set_version_on_aggregate_with_explicit_Version_attribute
    passes.
  * Full EventSourcingTests on net9.0: 1274 passed, 2 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 7c994bb into master May 12, 2026
6 checks passed
@jeremydmiller jeremydmiller deleted the revision-long-3733 branch May 12, 2026 19:51
jeremydmiller added a commit that referenced this pull request May 20, 2026
… (#4534)

* Marten docs: rewrite stale IRevisioned int->long migration-guide section for the #4533 revert

An early 9.0 alpha widened IRevisioned.Version to long; #4533 reverted that
before rc.1 (IRevisioned stays int, V8-compatible) and added ILongVersioned
(long) for MultiStreamProjection documents whose Version is the global event
sequence number. The migration guide still told users to widen Version to long.

Rewrite the section to lead with the reversal, introduce ILongVersioned with the
Int32-overflow rationale, and replace the widen-to-long example with a correct
IRevisioned(int)/ILongVersioned(long) pair. Every Before|After type in the table
was verified against origin/master source: IRevisioned.Version is int (unchanged);
DocumentMetadata.CurrentRevision, UpdateRevision/TryUpdateRevision parameters,
IRevisionedOperation.Revision and the m.Revision metadata column are long (and
source-compatible via int->long). Dropped the stale claim that MapTo to an int
property throws (RevisionColumn now accepts int or long). References updated to
#4533 / #4526 / #4528 / #348; #3733 / #4377 are historical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Marten docs: regenerate concurrency.md sample_versioned_reservation snippet (int Version)

The embedded sample_versioned_reservation snippet still showed long Version even
though its source (src/Marten.Testing/Examples/RevisionedDocuments.cs) was already
reverted to int by #4533. Regenerated via mdsnippets so the embed matches source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revision needs to be a long and not an int in all usages

1 participant