diff --git a/src/Marten/Linq/Parsing/Methods/MemoryExtensionsContains.cs b/src/Marten/Linq/Parsing/Methods/MemoryExtensionsContains.cs index cb2044e5cb..03a5793c85 100644 --- a/src/Marten/Linq/Parsing/Methods/MemoryExtensionsContains.cs +++ b/src/Marten/Linq/Parsing/Methods/MemoryExtensionsContains.cs @@ -1,9 +1,12 @@ #nullable enable using System; +using System.Collections; +using System.Linq; using System.Linq.Expressions; using Marten.Exceptions; using Marten.Linq.Members; using Marten.Linq.QueryHandlers; +using Weasel.Postgresql; using Weasel.Postgresql.SqlGeneration; namespace Marten.Linq.Parsing.Methods; @@ -30,6 +33,31 @@ public ISqlFragment Parse(IQueryableMemberCollection memberCollection, IReadOnly { // This is the constant.Contains(value) pattern var collectionMember = memberCollection.MemberFor(expression.Arguments[1]); + + // #4610 mirror: on net10.0 the C# compiler resolves `array.Contains(x)` to + // MemoryExtensions.Contains (via the implicit array → ReadOnlySpan conversion), + // routing the same shape that EnumerableContains handles on net9 through this + // parser instead. The enum case has the same Npgsql parameter-mapping problem + // (`Writing values of 'EnumType[]' is not supported for parameters having + // NpgsqlDbType '-2147483639'`) and the same fix: project the constant + // collection through EnumIsOneOfWhereFragment so it becomes a string[]/int[] + // with the right NpgsqlDbType for the active EnumStorage. + if (collectionMember.MemberType.IsEnum && constant.Value is not null) + { + // EnumIsOneOfWhereFragment requires a System.Array; for net10's + // ReadOnlySpan path the captured value is still the original array, but + // a hand-written List.Contains-via-MemoryExtensions shape + // could land here too, so guard the conversion the same way. + var arrayValue = constant.Value is Array + ? constant.Value + : ((IEnumerable)constant.Value).Cast().ToArray(); + + return new EnumIsOneOfWhereFragment( + arrayValue, + options.Serializer().EnumStorage, + collectionMember.TypedLocator); + } + return new IsOneOfFilter(collectionMember, new CommandParameter(constant.Value)); }