Skip to content

Commit 338b76a

Browse files
authored
Take into account Contains item visitation in SqlNullabilityProcessor (#32214)
Fixes #32208
1 parent 5be4798 commit 338b76a

File tree

6 files changed

+71
-1
lines changed

6 files changed

+71
-1
lines changed

src/EFCore.Relational/Query/SqlNullabilityProcessor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ protected virtual SqlExpression VisitIn(InExpression inExpression, bool allowOpt
649649
// SQL IN returns null when the item is null, and when the values (or subquery projection) contains NULL and no match was made.
650650

651651
var item = Visit(inExpression.Item, out var itemNullable);
652+
inExpression = inExpression.Update(item, inExpression.Subquery, inExpression.Values, inExpression.ValuesParameter);
652653

653654
if (inExpression.Subquery != null)
654655
{

test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,20 @@ public virtual Task Project_primitive_collections_element(bool async)
807807
},
808808
assertOrder: true);
809809

810+
[ConditionalTheory] // #32208
811+
[MemberData(nameof(IsAsyncData))]
812+
public virtual Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
813+
{
814+
var ints = new List<int> { 1, 2, 3 };
815+
var strings = new List<string> { "one", "two", "three" };
816+
817+
// Note that in this query, the outer Contains really has no type mapping, neither for its source (collection parameter), nor
818+
// for its item (the conditional expression returns constants). The default type mapping must be applied.
819+
return AssertQuery(
820+
async,
821+
ss => ss.Set<PrimitiveCollectionsEntity>().Where(e => strings.Contains(ints.Contains(e.Int) ? "one" : "two")));
822+
}
823+
810824
public abstract class PrimitiveCollectionsQueryFixtureBase : SharedStoreFixtureBase<PrimitiveCollectionsContext>, IQueryFixtureBase
811825
{
812826
private PrimitiveArrayData? _expectedData;

test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,21 @@ ORDER BY [p].[Id]
610610
""");
611611
}
612612

613+
public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
614+
{
615+
await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
616+
617+
AssertSql(
618+
"""
619+
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]
620+
FROM [PrimitiveCollectionsEntity] AS [p]
621+
WHERE CASE
622+
WHEN [p].[Int] IN (1, 2, 3) THEN N'one'
623+
ELSE N'two'
624+
END IN (N'one', N'two', N'three')
625+
""");
626+
}
627+
613628
[ConditionalFact]
614629
public virtual void Check_all_tests_overridden()
615630
=> TestHelpers.AssertAllMethodsOverridden(GetType());

test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,26 @@ ORDER BY [p].[Id]
12271227
""");
12281228
}
12291229

1230+
public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
1231+
{
1232+
await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
1233+
1234+
AssertSql(
1235+
"""
1236+
@__strings_0='["one","two","three"]' (Size = 4000)
1237+
1238+
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]
1239+
FROM [PrimitiveCollectionsEntity] AS [p]
1240+
WHERE CASE
1241+
WHEN [p].[Int] IN (1, 2, 3) THEN N'one'
1242+
ELSE N'two'
1243+
END IN (
1244+
SELECT [s].[value]
1245+
FROM OPENJSON(@__strings_0) WITH ([value] nvarchar(max) '$') AS [s]
1246+
)
1247+
""");
1248+
}
1249+
12301250
[ConditionalFact]
12311251
public virtual void Check_all_tests_overridden()
12321252
=> TestHelpers.AssertAllMethodsOverridden(GetType());

test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public override void Scalar_Function_with_nested_InExpression_translation()
336336
SELECT [c].[Id], [c].[FirstName], [c].[LastName]
337337
FROM [Customers] AS [c]
338338
WHERE CASE
339-
WHEN SUBSTRING([c].[FirstName], 0 + 1, 1) IN (N'A', N'B', N'C') THEN CAST(1 AS bit)
339+
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)
340340
ELSE CAST(0 AS bit)
341341
END IN (CAST(1 AS bit), CAST(0 AS bit))
342342
""");

test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,26 @@ public override async Task Project_empty_collection_of_nullables_and_collection_
11091109
(await Assert.ThrowsAsync<InvalidOperationException>(
11101110
() => base.Project_empty_collection_of_nullables_and_collection_only_containing_nulls(async))).Message);
11111111

1112+
public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async)
1113+
{
1114+
await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async);
1115+
1116+
AssertSql(
1117+
"""
1118+
@__strings_0='["one","two","three"]' (Size = 21)
1119+
1120+
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"
1121+
FROM "PrimitiveCollectionsEntity" AS "p"
1122+
WHERE CASE
1123+
WHEN "p"."Int" IN (1, 2, 3) THEN 'one'
1124+
ELSE 'two'
1125+
END IN (
1126+
SELECT "s"."value"
1127+
FROM json_each(@__strings_0) AS "s"
1128+
)
1129+
""");
1130+
}
1131+
11121132
[ConditionalFact]
11131133
public virtual void Check_all_tests_overridden()
11141134
=> TestHelpers.AssertAllMethodsOverridden(GetType());

0 commit comments

Comments
 (0)