GH-3531: cover EF Core + Marten conjoined tenancy in one database - #4043
Merged
Conversation
Every existing conjoined battery gives EF Core the database to itself. A real Critter Stack app does not, so this adds the mixed-persistence coverage: Wolverine-managed conjoined EF tenancy with PartitionPerTenant and Marten conjoined tenancy with Marten-managed partitioning, against ONE Postgres database, each in its own schema. Four tests, all asserted against pg_catalog rather than against either engine's own API -- an engine reporting on its own partitions cannot show that it left the other one alone: - each_engine_keeps_its_control_tables_in_its_own_schema: wolverine_tenants and wolverine_tenant_partitions in the Wolverine schema, mt_tenant_partitions in Marten's, and neither appears in the other's schema or in EF's. - registering_a_tenant_with_wolverine_partitions_only_the_ef_table: adding a tenant through AddWolverineManagedTenantsAsync creates the partition on mixed_items and leaves Marten's document table byte-for-byte as it was. - registering_a_tenant_with_marten_does_not_partition_the_ef_table: the mirror, through AddMartenManagedTenantsAsync. - cross_tenant_isolation_holds_for_both_engines_in_one_database: an EF entity and a Marten document written per tenant, each readable only by its own tenant, from the same database. Scenario 2 of the issue (EF + Polecat) is not here. Its stated gate -- JasperFx/polecat#335 -- has since closed, so it is unblocked, but it needs a Wolverine.Polecat reference this project does not carry and is better as its own change than bolted onto this one. One finding worth its own issue: .IntegrateWithWolverine() cannot currently be combined with conjoined EF tenancy. Handing envelope storage to Marten leaves ConjoinedDbContextBuilder unable to resolve a connection string -- it reads _database.Settings.ConnectionString from the Wolverine message store, and Marten's store surfaces none -- so the host dies at startup with "Unable to determine the database connection string for the conjoined multi-tenanted DbContext". These tests therefore keep Wolverine on its own Postgres message store, which does not weaken them: they are about partition and tenant OWNERSHIP between the engines, not about who owns envelope storage. The constraint is recorded in the file where the next reader will hit it. Verified: EfCoreTests.MultiTenancy 197 tests, 0 failed (193 before these four). wolverine.slnx -c Release -f net9.0 clean. No new CI target needed -- this project already runs under CIEfCore and already referenced Wolverine.Marten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
Author
|
Filed the Short version: The comment in this PR pointing at the constraint now references #4044. |
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.
Covers scenario 1 of #3531.
Every existing conjoined battery gives EF Core the database to itself. A real Critter Stack app does not. This adds the mixed-persistence coverage the issue asks for: Wolverine-managed conjoined EF tenancy with
PartitionPerTenant, and Marten conjoined tenancy with Marten-managed partitioning, against one Postgres database, each in its own schema.Asserted against
pg_catalog, not against either engineThis is the design decision worth reviewing. Every assertion reads
pg_inherits/pg_tablesdirectly rather than asking Wolverine or Marten what they think they did — because an engine reporting on its own partitions cannot show that it left the other one alone, which is the entire question the issue poses.each_engine_keeps_its_control_tables_in_its_own_schemawolverine_tenants+wolverine_tenant_partitionsin the Wolverine schema,mt_tenant_partitionsin Marten's, neither in the other's or in EF'sregistering_a_tenant_with_wolverine_partitions_only_the_ef_tableAddWolverineManagedTenantsAsyncpartitionsmixed_itemsand leaves Marten's document table exactly as it wasregistering_a_tenant_with_marten_does_not_partition_the_ef_tableAddMartenManagedTenantsAsynccross_tenant_isolation_holds_for_both_engines_in_one_databaseA finding that probably wants its own issue
.IntegrateWithWolverine()cannot currently be combined with conjoined EF tenancy. Handing envelope storage to Marten leavesConjoinedDbContextBuilderunable to resolve a connection string — it reads_database.Settings.ConnectionStringfrom the Wolverine message store, and Marten's store surfaces none — so the host dies at startup with:That is a plausible real-world combination (Marten for envelopes + conjoined EF for entities), so it looks like a genuine gap rather than an unsupported pairing. These tests therefore keep Wolverine on its own Postgres message store, which does not weaken them — they are about partition and tenant ownership between the engines, not about who owns envelope storage. The constraint is recorded in a comment at the exact place the next reader will hit it. Happy to file it separately.
Scenario 2 (EF + Polecat) is not here
Its stated gate, JasperFx/polecat#335, has since closed, so it is genuinely unblocked now. But it needs a
Wolverine.Polecatreference this test project does not carry, and it is better as its own change than bolted onto this one.Verified
EfCoreTests.MultiTenancy: 197 tests, 0 failed (193 before these four).dotnet build wolverine.slnx -c Release -f net9.0clean.CIEfCoreand already referencedWolverine.Marten, so nothing has to be wired into a workflow (and GH-3816: fail the build when a CI target runs nowhere #4037's guard would have caught it if it did).Two notes from building it, in case they save someone time later:
MixedDocneedsm.Schema.For<MixedDoc>().MultiTenanted()— with onlyRegisterDocumentTypeit is single-tenant, so Marten creates no partitions and isolation silently does not apply. And Marten and EF Core both ship anAnyAsyncextension, so a file that sees both must qualify the call.🤖 Generated with Claude Code