Fix value.Contains(enumMember) execution failure on enum document members#4610
Merged
Conversation
EnumerableContains.Parse built `new CommandParameter(constant.Value)` from the
raw constant — when the document member is a CLR enum, that's an `EnumType[]`
(or `List<EnumType>`) which Npgsql has no parameter mapping for, so the query
threw at execution time:
Writing values of 'YourEnum[]' is not supported for parameters
having NpgsqlDbType '-2147483639'.
This affected both EnumStorage.AsString and EnumStorage.AsInteger because the
parser path didn't route through any enum-aware conversion. The headline shape
is HotChocolate's `[UseFiltering]` `in` operator, which emits
`values.Contains(p.EnumMember)`.
The parallel `LinqExtensions.IsOneOf` path already handled enums via
`EnumIsOneOfWhereFragment` (IsOneOf.cs:36) — this routes the Contains shape
through the same fragment, projecting the constant collection into a string[]
(for AsString) or int[] (for AsInteger) with the correct NpgsqlDbType.
List<T> support: EnumIsOneOfWhereFragment requires a System.Array, so a
`List<EnumType>` constant is converted up front via `Cast<object>().ToArray()`.
Repro test covers: scalar-eq canary (must keep working), array Contains,
List<> Contains, single-element collection, empty collection boundary, and
AsInteger canary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller
added a commit
that referenced
this pull request
Jun 3, 2026
…sions #4610 fixed `values.Contains(p.EnumMember)` against an EnumStorage.AsString document member by routing the case through `EnumIsOneOfWhereFragment` in `EnumerableContains.Parse`. That worked on net9.0 but the regression test file failed on net10.0 in CI for PR #4613 and #4615 with the same `Writing values of 'YourEnum[]' is not supported for parameters having NpgsqlDbType '-2147483639'` shape from the original bug. Root cause: on net10.0 the C# compiler resolves `array.Contains(x)` to `MemoryExtensions.Contains` (via the implicit `T[]` → `ReadOnlySpan<T>` conversion), not `Enumerable.Contains`. The match runs through `MemoryExtensionsContains.Parse`, not `EnumerableContains.Parse`, and the former had the identical enum-array-as-raw-CommandParameter bug — #4610's fix had only patched the latter. Mirror the same fix into `MemoryExtensionsContains.Parse`. The existing Bug_enum_asstring_array_contains regression tests now cover both parsers because they target the user-facing shape (`values.Contains(p.Status)`) and each .NET version routes that to a different parser. Verified: - Bug_enum_asstring_array_contains: 6/6 pass on net9.0 - Bug_enum_asstring_array_contains: 6/6 pass on net10.0 - Full LinqTests on net10.0: 1269 passed, 0 failed Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Jun 3, 2026
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.
Problem
A user-reported execution-time bug: with a CLR
enumdocument member and anin/Contains-shaped LINQ predicate (the form HotChocolate's[UseFiltering]inoperator emits), the parsed query throws at execution with:Distinct from the parse-time #4599 / #4600 / #4601 family already shipped in 8.37.2 — this is downstream, at parameter-bind time.
Root cause
EnumerableContains.Parsebuilds:When the document member is an enum,
constant.Valueis a CLREnumType[](orList<EnumType>). Npgsql has no parameter mapping for an arbitrary enum array unless the enum is a registered Postgres enum type, so it fails at the parameter-bind step withNpgsqlDbType '-2147483639'(=Array | <ordinal 9>).The parallel
LinqExtensions.IsOneOfpath already handled this exact case viaEnumIsOneOfWhereFragment(IsOneOf.cs:36), which projects the array intostring[](forEnumStorage.AsString) orint[](forAsInteger) with the rightNpgsqlDbType. The Contains shape just didn't route through it.The bug was actually broader than the user reported: both
AsStringandAsIntegerenum-storage modes were affected on theContainspath — the AsString user reported it because that's the more common config.Fix
Route the enum case in
EnumerableContains.ParsethroughEnumIsOneOfWhereFragment, mirroringIsOneOf.cs:36. A smallList<T>→T[]coercion handles non-array constant collections, sinceEnumIsOneOfWhereFragmentrequires aSystem.Array.Tests
New
Bug_enum_asstring_array_containscovers:==canary on AsString — must keep working (already worked, but pinned).Containson AsString — headline regression.List<>Containson AsString — the non-array constant shape.Containson AsInteger — the broader half of the bug; pinned as a canary going forward.Pre-fix: all 5 Contains tests fail with the reported
Writing values of … is not supported. Post-fix: all 6 pass.Regression sweeps: full
LinqTests(1269 passed) + fullValueTypeTests(339 passed) — strongly-typed IDs share theEnumerableContainsparse path so worth pinning.🤖 Generated with Claude Code