Skip to content

Commit bf84a12

Browse files
committed
Reference types returns null instead of throwing for empty collections
1 parent ce43e29 commit bf84a12

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ private MethodCallExpression TryNormalizeMaxByMinBy(MethodCallExpression methodC
776776

777777
var keySelector = methodCallExpression.Arguments[1].UnwrapLambdaFromQuote();
778778

779-
var firstMethod = sourceType.IsNullableValueType()
779+
var firstMethod = sourceType.IsNullableType()
780780
? QueryableMethods.FirstOrDefaultWithoutPredicate
781781
: QueryableMethods.FirstWithoutPredicate;
782782

test/EFCore.Cosmos.FunctionalTests/Query/NorthwindAggregateOperatorsQueryCosmosTest.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,24 @@ OFFSET 0 LIMIT 1
707707
}
708708
}
709709

710+
public override async Task MaxBy_no_data_reference_type_source(bool async)
711+
{
712+
// Always throws for sync.
713+
if (async)
714+
{
715+
await base.MaxBy_no_data_reference_type_source(async);
716+
717+
AssertSql(
718+
"""
719+
SELECT VALUE c
720+
FROM root c
721+
WHERE ((c["$type"] = "Product") AND (c["SupplierID"] = -1))
722+
ORDER BY c["ProductID"] DESC
723+
OFFSET 0 LIMIT 1
724+
""");
725+
}
726+
}
727+
710728
public override async Task MaxBy_no_data_cast_to_nullable(bool async)
711729
{
712730
// Always throws for sync.
@@ -896,6 +914,24 @@ OFFSET 0 LIMIT 1
896914
}
897915
}
898916

917+
public override async Task MinBy_no_data_reference_type_source(bool async)
918+
{
919+
// Always throws for sync.
920+
if (async)
921+
{
922+
await base.MinBy_no_data_reference_type_source(async);
923+
924+
AssertSql(
925+
"""
926+
SELECT VALUE c
927+
FROM root c
928+
WHERE ((c["$type"] = "Product") AND (c["SupplierID"] = -1))
929+
ORDER BY c["ProductID"]
930+
OFFSET 0 LIMIT 1
931+
""");
932+
}
933+
}
934+
899935
public override async Task MinBy_no_data_cast_to_nullable(bool async)
900936
{
901937
// Always throws for sync.

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,13 @@ public virtual Task MinBy_no_data_nullable_source(bool async)
356356
ss => ss.Set<Product>().Where(o => o.SupplierID == -1).Select(o => o.SupplierID),
357357
selector: o => o ?? 0 /*non nullable selector*/);
358358

359+
[ConditionalTheory, MemberData(nameof(IsAsyncData))]
360+
public virtual Task MinBy_no_data_reference_type_source(bool async)
361+
=> AssertMinBy(
362+
async,
363+
ss => ss.Set<Product>().Where(o => o.SupplierID == -1),
364+
selector: o => o.ProductID);
365+
359366
[ConditionalTheory, MemberData(nameof(IsAsyncData))]
360367
public virtual Task MinBy_no_data_cast_to_nullable(bool async)
361368
=> Assert.ThrowsAsync<InvalidOperationException>(() => AssertMinBy(
@@ -417,6 +424,13 @@ public virtual Task MaxBy_no_data_nullable_source(bool async)
417424
ss => ss.Set<Product>().Where(o => o.SupplierID == -1).Select(o => o.SupplierID),
418425
selector: o => o ?? 0 /*non nullable selector*/);
419426

427+
[ConditionalTheory, MemberData(nameof(IsAsyncData))]
428+
public virtual Task MaxBy_no_data_reference_type_source(bool async)
429+
=> AssertMaxBy(
430+
async,
431+
ss => ss.Set<Product>().Where(o => o.SupplierID == -1),
432+
selector: o => o.ProductID);
433+
420434
[ConditionalTheory, MemberData(nameof(IsAsyncData))]
421435
public virtual Task MaxBy_no_data_cast_to_nullable(bool async)
422436
=> Assert.ThrowsAsync<InvalidOperationException>(() => AssertMaxBy(

test/EFCore.Specification.Tests/TestUtilities/ExpectedQueryRewritingVisitor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ private static Expression RewriteMaxByMinBy(MethodCallExpression methodCallExpre
213213

214214
if (methodCallExpression.Method.DeclaringType == typeof(Enumerable))
215215
{
216-
firstMethod = sourceType.IsNullableValueType()
216+
firstMethod = sourceType.IsNullableType()
217217
? EnumerableMethods.FirstOrDefaultWithoutPredicate
218218
: EnumerableMethods.FirstWithoutPredicate;
219219

@@ -225,7 +225,7 @@ private static Expression RewriteMaxByMinBy(MethodCallExpression methodCallExpre
225225
}
226226
else
227227
{
228-
firstMethod = sourceType.IsNullableValueType()
228+
firstMethod = sourceType.IsNullableType()
229229
? QueryableMethods.FirstOrDefaultWithoutPredicate
230230
: QueryableMethods.FirstWithoutPredicate;
231231

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ ORDER BY COALESCE([p].[SupplierID], 0)
389389
""");
390390
}
391391

392+
public override async Task MinBy_no_data_reference_type_source(bool async)
393+
{
394+
await base.MinBy_no_data_reference_type_source(async);
395+
396+
AssertSql(
397+
"""
398+
SELECT TOP(1) [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock]
399+
FROM [Products] AS [p]
400+
WHERE [p].[SupplierID] = -1
401+
ORDER BY [p].[ProductID]
402+
""");
403+
}
404+
392405
public override async Task MinBy_no_data_cast_to_nullable(bool async)
393406
{
394407
await base.MinBy_no_data_cast_to_nullable(async);
@@ -590,6 +603,19 @@ ORDER BY COALESCE([p].[SupplierID], 0) DESC
590603
""");
591604
}
592605

606+
public override async Task MaxBy_no_data_reference_type_source(bool async)
607+
{
608+
await base.MaxBy_no_data_reference_type_source(async);
609+
610+
AssertSql(
611+
"""
612+
SELECT TOP(1) [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock]
613+
FROM [Products] AS [p]
614+
WHERE [p].[SupplierID] = -1
615+
ORDER BY [p].[ProductID] DESC
616+
""");
617+
}
618+
593619
public override async Task MaxBy_no_data_cast_to_nullable(bool async)
594620
{
595621
await base.MaxBy_no_data_cast_to_nullable(async);

0 commit comments

Comments
 (0)