diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
index bac9615292c..31ebb08d3ab 100644
--- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
+++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
@@ -24,6 +24,9 @@ public class SqlNullabilityProcessor
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private bool _canCache;
+ private static readonly bool UseOldBehavior32208 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32208", out var enabled32208) && enabled32208;
+
///
/// Creates a new instance of the class.
///
@@ -650,6 +653,11 @@ protected virtual SqlExpression VisitIn(InExpression inExpression, bool allowOpt
var item = Visit(inExpression.Item, out var itemNullable);
+ if (!UseOldBehavior32208)
+ {
+ inExpression = inExpression.Update(item, inExpression.Subquery, inExpression.Values, inExpression.ValuesParameter);
+ }
+
if (inExpression.Subquery != null)
{
var subquery = Visit(inExpression.Subquery);
diff --git a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
index 943bf5b8af0..8c9b7d8ca4d 100644
--- a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs
@@ -807,6 +807,20 @@ public virtual Task Project_primitive_collections_element(bool async)
},
assertOrder: true);
+ [ConditionalTheory] // #32208
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
+ {
+ var ints = new List { 1, 2, 3 };
+ var strings = new List { "one", "two", "three" };
+
+ // Note that in this query, the outer Contains really has no type mapping, neither for its source (collection parameter), nor
+ // for its item (the conditional expression returns constants). The default type mapping must be applied.
+ return AssertQuery(
+ async,
+ ss => ss.Set().Where(e => strings.Contains(ints.Contains(e.Int) ? "one" : "two")));
+ }
+
public abstract class PrimitiveCollectionsQueryFixtureBase : SharedStoreFixtureBase, IQueryFixtureBase
{
private PrimitiveArrayData? _expectedData;
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
index 894782c9ee4..99f28eaca16 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs
@@ -610,6 +610,21 @@ ORDER BY [p].[Id]
""");
}
+ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
+ {
+ await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
+
+ AssertSql(
+ """
+SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
+FROM [PrimitiveCollectionsEntity] AS [p]
+WHERE CASE
+ WHEN [p].[Int] IN (1, 2, 3) THEN N'one'
+ ELSE N'two'
+END IN (N'one', N'two', N'three')
+""");
+ }
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
index 4f045e011cb..5de3656afe8 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs
@@ -1227,6 +1227,26 @@ ORDER BY [p].[Id]
""");
}
+ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
+ {
+ await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
+
+ AssertSql(
+ """
+@__strings_0='["one","two","three"]' (Size = 4000)
+
+SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
+FROM [PrimitiveCollectionsEntity] AS [p]
+WHERE CASE
+ WHEN [p].[Int] IN (1, 2, 3) THEN N'one'
+ ELSE N'two'
+END IN (
+ SELECT [s].[value]
+ FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s]
+)
+""");
+ }
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
index 0beb6a55cdf..d3bce765060 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
@@ -336,7 +336,7 @@ public override void Scalar_Function_with_nested_InExpression_translation()
SELECT [c].[Id], [c].[FirstName], [c].[LastName]
FROM [Customers] AS [c]
WHERE CASE
- WHEN SUBSTRING([c].[FirstName], 0 + 1, 1) IN (N'A', N'B', N'C') THEN CAST(1 AS bit)
+ WHEN SUBSTRING([c].[FirstName], 0 + 1, 1) IN (N'A', N'B', N'C') AND SUBSTRING([c].[FirstName], 0 + 1, 1) IS NOT NULL THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END IN (CAST(1 AS bit), CAST(0 AS bit))
""");
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
index a6eb534b7b4..22f87566b86 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
@@ -1109,6 +1109,26 @@ public override async Task Project_empty_collection_of_nullables_and_collection_
(await Assert.ThrowsAsync(
() => base.Project_empty_collection_of_nullables_and_collection_only_containing_nulls(async))).Message);
+ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
+ {
+ await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
+
+ AssertSql(
+ """
+@__strings_0='["one","two","three"]' (Size = 21)
+
+SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."String", "p"."Strings"
+FROM "PrimitiveCollectionsEntity" AS "p"
+WHERE CASE
+ WHEN "p"."Int" IN (1, 2, 3) THEN 'one'
+ ELSE 'two'
+END IN (
+ SELECT "s"."value"
+ FROM json_each(@__strings_0) AS "s"
+)
+""");
+ }
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());