You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Persistence provider resolution: EF Core must be evaluated before Marten when both are registered (Marten's blanket CanPersist wins on registration order) #3359
Spun out of #3353 (see "Separately..." in that issue's report) so it doesn't get lost.
Summary
GenerationRulesExtensions.TryFindPersistenceFrameProvider resolves the provider for a storage action / [Entity] load by filtering PersistenceProviders() with CanPersist and taking candidates.First() (src/Wolverine/Persistence/Sagas/GenerationRulesExtensions.cs:61-78). Two facts make that order-dependent in mixed Marten + EF Core applications:
MartenPersistenceFrameProvider.CanPersist returns true for every type (src/Persistence/Wolverine.Marten/Persistence/Sagas/MartenPersistenceFrameProvider.cs:24-28) — Marten can genuinely persist any document, so it claims anything it is asked about.
Provider order is set by InsertFirstPersistenceStrategy from each integration's IWolverineExtension, and extensions are applied in DI registration order — so whichever integration the application happens to register last sits at index 0 and claims every entity.
Consequence: in a Marten + EF Core application, a Storage.Insert(entity) / IStorageAction<T> / [Entity] over an EF-mapped entity resolves to Marten (generating IDocumentSession code against a type the app persists with EF Core) or to EF Core purely depending on whether AddMarten().IntegrateWithWolverine() appears before or after AddDbContextWithWolverineIntegration<T>() in Program.cs. The #3353 report hit this directly: its first reproducer needed an extension that manually reordered PersistenceProviders() because Marten silently claimed the EF-mapped entity.
The chain-level twin, GetPersistenceProviders(chain, container) → FirstOrDefault(x => x.CanApply(chain, container)), has the same ordering sensitivity.
Desired behavior
EF Core must be evaluated before Marten whenever both are active, regardless of user registration order. EF Core's CanPersist is selective — it answers true only for types actually mapped in a registered DbContext model — while Marten's is a catch-all. With EF Core first, EF-mapped entities deterministically resolve to their DbContext and everything else still falls through to Marten; nothing that only Marten can persist is ever taken away from it.
Implementation options, in rough order of preference:
Give the provider list a deterministic ordering rule: selective providers (EF Core, and any provider whose CanPersist inspects the type) ahead of catch-all providers (Marten, Polecat?), applied when the list is consulted rather than trusting insertion order.
Or have the Marten integration register itself with lowest precedence (append rather than InsertFirst) / have the EF Core integration force itself ahead of Marten at bootstrap.
Test automation
Whatever the mechanism, this needs registration-order permutation tests: Marten-then-EFCore and EFCore-then-Marten hosts, each asserting (a) a storage action / [Entity] over a DbContext-mapped entity generates DbContext code, and (b) a non-EF-mapped document still resolves to Marten. The Wolverine.Http.Tests.EfCoreOnly + pinned-ApplicationAssembly pattern from #3357 can host the HTTP variants without disturbing the main test assembly.
Activity
Evaluate the EF Core persistence provider before Marten regardless of…
Add explicit per-provider entity attributes, starting with [FromMarte…
GH-4631: fail loudly when two persistence providers can own one chain (…