Skip to content

Scope the Postgres enum registrations to the EF Core service provider - #5

Merged
dmytro-khmara merged 1 commit into
masterfrom
fix-postgres-enum-mapping-race
Aug 13, 2026
Merged

Scope the Postgres enum registrations to the EF Core service provider#5
dmytro-khmara merged 1 commit into
masterfrom
fix-postgres-enum-mapping-race

Conversation

@dmytro-khmara

Copy link
Copy Markdown
Member

Summary

Makes RawSqlEnumParameterTests stop failing intermittently in CI with 42804: column "Sport" is of type sport but expression is of type text.

The store-type lookup lived in a process-wide static StringEnumPgTypeRegistry, while EF Core memoises the first FindMapping(typeof(TEnum), storeType: null) result in a cache owned by the internal service provider. Because StrEnumNpgsqlOptionsExtension keyed every configuration to the same provider, all four integration-test contexts shared one type-mapping cache. Whichever context built its model first won: if one that had not registered an enum got there first, EF memoised the miss and served it to the context that had registered, so raw-SQL parameters fell back to text. Test classes run in parallel, hence the flakiness.

The fix scopes the registrations to the service provider that owns the cache:

  • StringEnumPostgresEnumRegistrar accumulates its registrations instead of writing to a static, and the options extension carries them.
  • NpgsqlStringEnumTypeMappingSourcePlugin takes that map by constructor and resolves against it, so a plugin instance only ever sees its own context's registrations.
  • StringEnumPgTypeRegistry is deleted; StringEnumPgTypeKey holds the shared key format.

One behaviour change worth noting: HasPostgresStringEnum / MapStringEnumAsPostgresEnum no longer feed the raw-SQL parameter path, because model-level configuration runs inside OnModelCreating — after EF has already memoised the (TEnum, null) lookup. That path never worked reliably; it is the race this PR removes. Up-front registration via UseStringEnumsAsPostgresEnums(r => r.MapStringEnum<TEnum>()) remains the supported way to bind string enums on the raw-SQL path, exactly as RawSqlEnumParameterTests already does. Property-driven mapping is unaffected.

Test plan

  • Integration suite run 15 times consecutively: 15 passed, 0 failed. Before the fix the same suite failed 2 of 5 runs, and 1 of 10 after only keying the provider hash code
  • dotnet test — 29 unit and 6 integration tests pass
  • docker build --target test . passes
  • New StrEnumNpgsqlOptionsExtensionTests cover provider keying: same registrations share a provider; differing registrations, differing enum names, and differing enums do not
  • NpgsqlStringEnumTypeMappingSourcePluginTests updated to construct the plugin with explicit registrations rather than mutating global state

@dmytro-khmara
dmytro-khmara merged commit bd2c209 into master Aug 13, 2026
2 checks passed
@dmytro-khmara
dmytro-khmara deleted the fix-postgres-enum-mapping-race branch August 13, 2026 22:40
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.

1 participant