Skip to content

Migration Guide

Key Changes in 7.0.0

The V7 release significantly impacted Marten internals and also included support for .NET 8 and and upgrade to Npgsql 8. In addition, Marten 7.0 requires at least PostgreSQL 12 because of the dependence upon sql/json constructs introduced in PostgreSQL 12.

Marten 7 includes a large overhaul of the LINQ provider support, with highlights including:

  • Very significant improvements to querying through document child collections by being able to opt into JSONPath or containment operator querying in many cases. Early reports suggest an order of magnitude improvement in query times.
  • GIST/GIN indexes should be effective with Marten queries again
  • The IMethodCallParser interface changed slightly, and any custom implementations will have to be adjusted
  • Covers significantly more use cases within the LINQ Where() filtering
  • Select() support was widened to include constructor functions

The database connection lifetime logic in IDocumentSession or IQuerySession was changed from the original Marten 1-6 "sticky" connection behavior. Instead of Marten trying to keep a database connection open from first usage through any call to SaveChangesAsync(), Marten is auto-closing the connection on every usage by default. This change should help reduce the overall number of open connections used at runtime, and help make Marten be more easily integrated into GraphQL solutions using the Hot Chocolate framework.

See Connection Handling for more information, including how to opt into the previous V6 and earlier "sticky" connection lifetime.

Marten 7 replaces the previous IRetryPolicy mechanism for resiliency with built in support for Polly. See Resiliency Policies for more information.

Key Changes in 6.0.0

The V6 release lite motive is upgrading to .NET 7 and Npgsql 7. Besides that, we decided to align the event sourcing projections' naming and initializing document sessions. See the full release notes.

We tried to limit the number of breaking changes and mark methods with obsolete attributes to promote the new recommended way.

The scope of breaking changes is limited, but we highly encourage migrating from all obsolete usage to the new conventions.

Guide on migration from v5 to v6:

  • We Dropped support of .NET Core 3.1 and .NET 5 following the Official .NET Support Policy. That allowed us to benefit fully from recent .NET improvements around asynchronous code, performance etc. Plus made maintenance easier by removing branches of code. If you're using those .NET versions, you need to upgrade to .NET 6 or 7.
  • Upgraded Npgsql version to 7. If your project uses an explicitly lower version of Npgsql than 7, you'll need to bump it. We didn't face substantial issues this time, so you might not need to do around it, but you can double-check in the Npgsql 7 release notes for detailed information about breaking changes on their side.
  • Generic OpenSession store options (OpenSession(SessionOptions options) does not track changes by default. Previously, it was using identity map. Other overloads of OpenSession didn't change the default behavior but were made obsolete. We encourage using explicit session creation and LightweightSession by default, as in the next major version, we plan to do the full switch. Read more about the Unit of Work mechanics.
  • Renamed asynchronous session creation to include explicit Serializable name. OpenSessionAsync was misleading, as the intention behind it was to enable proper handling of Postgres' serialized transaction level. Renamed the method to OpenSerializableSessionAsync and added explicit methods for session types. Check more in handling Transaction Isolation Level.
  • Removed obsolete methods marked as to be removed in the previous versions.:
    • Removed synchronous'BuildProjectionDaemonfrom theIDocumentStore` method. Use the asynchronous version instead.
    • Removed Schema from IDocumentStore. Use Storage instead.
    • Replaced GroupEventRange in IAggregationRuntime with Slicer reference.
    • Removed unused UseAppendEventForUpdateLock setting.
    • Removed the Searchable method from MartenRegistry. Use Index instead. ASP.NET JSON streaming WriteById is now using correctly custom onFoundStatus. We had the bug and always used the default status. It's enhancement but also technically a breaking change to the behavior. We also added onFoundStatus to other methods, so you could specify, e.g. 201 Created status for creating a new record.
  • Added Optimistic concurrency checks during documents' updates. Previously, they were only handled when calling the Store method; now Update uses the same logic.
  • Base state passed as parameter is returned from AggregateStreamAsync instead of null when the stream is empty. AggregateStreamAsync allows passing the default state on which we're applying events. When no events were found, we were always returning null. Now we'll return the passed value. It is helpful when you filter events from a certain version or timestamp. It'll also be useful in the future for archiving scenarios
  • Ensured events with both Create and Apply in stream aggregation were handled only once. When you defined both Create and Apply methods for the specific event, both methods were called for the single event. That wasn't expected behavior. Now they'll be only handled once.
  • Added missing passing Cancellation Tokens in all async methods in public API. That ensures that cancellation is handled correctly across the whole codebase. Added the static analysis to ensure we won't miss them in the future.
  • All the Critter Stack dependencies like Weasel, Lamar, JasperFx.Core, Oakton, and JasperFx.CodeGeneration were bumped to the latest major versions. If you use them explicitly, you'll need to align the versions.

Besides that, non-breaking but important changes to upgrade are:

  • Added explicit LightweightSession and IdentitySession creation methods to DocumentStore. Previously you could create DirtyTrackedSession explicitly. Now you can create all types of sessions explicitly. We recommend using them explicitly instead of the generic OpenSession method.
  • Renamed aggregations into projections and SelfAggregate into Snapshot and LiveStreamAggregation. The established terms in the Event Sourcing community are Projection and Snapshot. Even though our naming was more precise on the implementation behind the scenes, it could be confusing. We decided to align it with the common naming and be more explicit about the intention. Old methods were marked as obsolete and will be removed in the next major release.

Other notable new features:

  • Added support for reusing Documents in the same async projection batch. By default, Marten does batch to handle multiple events for the projection in one update. When using EventProjection and updating data manually using IDocumentOperations, this may cause changes made for previous batch items not to be visible. Now you can opt-in for tracking documents by an identity within a batch using the EnableDocumentTrackingByIdentity async projection option. Read more in related docs.
  • Enabled the possibility of applying projections with different Conjoined Tenancy scopes for projections. Enabled global projection for events with a conjoined tenancy style. Read more in multi-tenancy documentation
  • Added automatic retries when schema updates are running in parallel. Marten locks the schema update using advisory locks. Previously when acquiring lock failed, then schema update also failed. Now it will be retried, which enables easier parallel automated tests and running schema migration during the startup for the containerized environment.

Key Changes in 5.0.0

V5 was a much smaller release for Marten than V4, and should require much less effort to move from V4 to V5 as it did from V2/3 to V4.

Key Changes in 4.0.0

V4 was a very large release for Marten, and basically every subsystem was touched at some point. When you are upgrading from V2/3 to V4 -- and even earlier alphas or RC releases of 4.0 -- you will need to run a database migration as part of your migration to V4.

Other key, breaking changes:

  • All schema management methods, including assertions on the schema, are now asynchronous. We had to do this for Npgsql connection multiplexing.
  • The compiled query syntax changed
  • The event store support has quite a few additions
  • Projections in Marten have moved to an all new programming model. Some of it is at least similar, but read the documentation on projection types before moving a Marten application over
  • The async daemon was completely rewritten, and is now about to run in application clusters and handle multi-tenancy
  • A few diagnostic methods moved within the API
  • Document types need to be public now, and Marten will alert you if document types are not public
  • The dynamic code in Marten moved to a runtime code generation model. If this is causing you any issues with cold start times or memory usage due to Roslyn misbehaving (this is not consistent), there is the new "generate ahead model" as a workaround.
  • If an application bootstraps Marten through the IServiceCollection.AddMarten() extension methods, the default logging in Marten is through the standard ILogger of the application
  • In order to support more LINQ query permutations, LINQ queries are temporarily not using the GIN indexable operators on documents that have GinIndexJsonData() set. Support for this can be tracked here
  • PLV8 support is disabled by default and moved to a separate package. If an application was setting StoreOptions.PLV8Enabled = false to disable PLV8, that line should be removed as the setting no longer exists. If an application had StoreOptions.PLV8Enabled = true and was using PLV8, you will need to add the Marten.PLv8 package.

Key Changes in 3.0.0

Main goal of this release was to accommodate the Npgsql 4.* dependency.

Besides the usage of Npgsql 4, our biggest change was making the default schema object creation mode to CreateOrUpdate. Meaning that Marten even in its default mode will not drop any existing tables, even in development mode. You can still opt into the full "sure, I’ll blow away a table and start over if it’s incompatible" mode, but we felt like this option was safer after a few user problems were reported with the previous rules. See schema migration and patches for more information.

We also aligned usage of EnumStorage. Previously, Enum duplicated fields was always stored as varchar. Now it's using setting from JsonSerializer options - so by default it's integer. We felt that it's not consistent to have different default setting for Enums stored in json and in duplicated fields.

See full list of the fixed issues on GitHub.

You can also read more in Jeremy's blog post from.

Migration from 2.*

  • To keep Marten fully rebuilding your schema (so to allow Marten drop tables) set store options to:
AutoCreateSchemaObjects = AutoCreate.All
  • To keep enum fields being stored as varchar set store options to:
DuplicatedFieldEnumStorage = EnumStorage.AsString;
DuplicatedFieldUseTimestampWithoutTimeZoneForDateTime = false;

Released under the MIT License.