@@ -444,7 +444,25 @@ private ShapedQueryExpression CreateShapedQueryExpression(SelectExpression selec
444444 /// </summary>
445445 protected override ShapedQueryExpression ? TranslateAverage ( ShapedQueryExpression source , LambdaExpression ? selector , Type resultType )
446446 {
447- var selectExpression = ( SelectExpression ) source . QueryExpression ;
447+ var updatedSource = TranslateAggregateCommon ( source , selector , resultType , out var selectExpression ) ;
448+ if ( updatedSource == null )
449+ {
450+ return null ;
451+ }
452+
453+ var projection = ( SqlExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) ;
454+ projection = _sqlExpressionFactory . Function ( "AVG" , new [ ] { projection } , resultType , _typeMappingSource . FindMapping ( resultType ) ) ;
455+
456+ return AggregateResultShaper ( updatedSource , projection , resultType ) ;
457+ }
458+
459+ private ShapedQueryExpression ? TranslateAggregateCommon (
460+ ShapedQueryExpression source ,
461+ LambdaExpression ? selector ,
462+ Type resultType ,
463+ out SelectExpression selectExpression )
464+ {
465+ selectExpression = ( SelectExpression ) source . QueryExpression ;
448466 if ( selectExpression . IsDistinct
449467 || selectExpression . Limit != null
450468 || selectExpression . Offset != null )
@@ -457,10 +475,13 @@ private ShapedQueryExpression CreateShapedQueryExpression(SelectExpression selec
457475 source = TranslateSelect ( source , selector ) ;
458476 }
459477
460- var projection = ( SqlExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) ;
461- projection = _sqlExpressionFactory . Function ( "AVG" , new [ ] { projection } , resultType , _typeMappingSource . FindMapping ( resultType ) ) ;
478+ if ( resultType . IsNullableType ( ) )
479+ {
480+ // For nullable types, we want to return null from Max, Min, and Average, rather than throwing. See Issue #35094.
481+ source = source . UpdateResultCardinality ( ResultCardinality . SingleOrDefault ) ;
482+ }
462483
463- return AggregateResultShaper ( source , projection , throwOnNullResult : true , resultType ) ;
484+ return source ;
464485 }
465486
466487 /// <summary>
@@ -842,24 +863,17 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
842863 /// </summary>
843864 protected override ShapedQueryExpression ? TranslateMax ( ShapedQueryExpression source , LambdaExpression ? selector , Type resultType )
844865 {
845- var selectExpression = ( SelectExpression ) source . QueryExpression ;
846- if ( selectExpression . IsDistinct
847- || selectExpression . Limit != null
848- || selectExpression . Offset != null )
866+ var updatedSource = TranslateAggregateCommon ( source , selector , resultType , out var selectExpression ) ;
867+ if ( updatedSource == null )
849868 {
850869 return null ;
851870 }
852871
853- if ( selector != null )
854- {
855- source = TranslateSelect ( source , selector ) ;
856- }
857-
858872 var projection = ( SqlExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) ;
859873
860874 projection = _sqlExpressionFactory . Function ( "MAX" , new [ ] { projection } , resultType , projection . TypeMapping ) ;
861875
862- return AggregateResultShaper ( source , projection , throwOnNullResult : true , resultType ) ;
876+ return AggregateResultShaper ( updatedSource , projection , resultType ) ;
863877 }
864878
865879 /// <summary>
@@ -870,24 +884,17 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
870884 /// </summary>
871885 protected override ShapedQueryExpression ? TranslateMin ( ShapedQueryExpression source , LambdaExpression ? selector , Type resultType )
872886 {
873- var selectExpression = ( SelectExpression ) source . QueryExpression ;
874- if ( selectExpression . IsDistinct
875- || selectExpression . Limit != null
876- || selectExpression . Offset != null )
887+ var updatedSource = TranslateAggregateCommon ( source , selector , resultType , out var selectExpression ) ;
888+ if ( updatedSource == null )
877889 {
878890 return null ;
879891 }
880892
881- if ( selector != null )
882- {
883- source = TranslateSelect ( source , selector ) ;
884- }
885-
886893 var projection = ( SqlExpression ) selectExpression . GetMappedProjection ( new ProjectionMember ( ) ) ;
887894
888895 projection = _sqlExpressionFactory . Function ( "MIN" , new [ ] { projection } , resultType , projection . TypeMapping ) ;
889896
890- return AggregateResultShaper ( source , projection , throwOnNullResult : true , resultType ) ;
897+ return AggregateResultShaper ( updatedSource , projection , resultType ) ;
891898 }
892899
893900 /// <summary>
@@ -1241,7 +1248,7 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
12411248
12421249 projection = _sqlExpressionFactory . Function ( "SUM" , new [ ] { projection } , serverOutputType , projection . TypeMapping ) ;
12431250
1244- return AggregateResultShaper ( source , projection , throwOnNullResult : false , resultType ) ;
1251+ return AggregateResultShaper ( source , projection , resultType ) ;
12451252 }
12461253
12471254 /// <summary>
@@ -1695,7 +1702,6 @@ private Expression RemapLambdaBody(ShapedQueryExpression shapedQueryExpression,
16951702 private static ShapedQueryExpression AggregateResultShaper (
16961703 ShapedQueryExpression source ,
16971704 Expression projection ,
1698- bool throwOnNullResult ,
16991705 Type resultType )
17001706 {
17011707 var selectExpression = ( SelectExpression ) source . QueryExpression ;
@@ -1706,29 +1712,7 @@ private static ShapedQueryExpression AggregateResultShaper(
17061712 var nullableResultType = resultType . MakeNullable ( ) ;
17071713 Expression shaper = new ProjectionBindingExpression ( source . QueryExpression , new ProjectionMember ( ) , nullableResultType ) ;
17081714
1709- if ( throwOnNullResult )
1710- {
1711- var resultVariable = Expression . Variable ( nullableResultType , "result" ) ;
1712- var returnValueForNull = resultType . IsNullableType ( )
1713- ? ( Expression ) Expression . Constant ( null , resultType )
1714- : Expression . Throw (
1715- Expression . New (
1716- typeof ( InvalidOperationException ) . GetConstructors ( )
1717- . Single ( ci => ci . GetParameters ( ) . Length == 1 ) ,
1718- Expression . Constant ( CoreStrings . SequenceContainsNoElements ) ) ,
1719- resultType ) ;
1720-
1721- shaper = Expression . Block (
1722- new [ ] { resultVariable } ,
1723- Expression . Assign ( resultVariable , shaper ) ,
1724- Expression . Condition (
1725- Expression . Equal ( resultVariable , Expression . Default ( nullableResultType ) ) ,
1726- returnValueForNull ,
1727- resultType != resultVariable . Type
1728- ? Expression . Convert ( resultVariable , resultType )
1729- : resultVariable ) ) ;
1730- }
1731- else if ( resultType != shaper . Type )
1715+ if ( resultType != shaper . Type )
17321716 {
17331717 shaper = Expression . Convert ( shaper , resultType ) ;
17341718 }
0 commit comments