@@ -443,25 +443,7 @@ private ShapedQueryExpression CreateShapedQueryExpression(SelectExpression selec
443443    ///     doing so can result in application failures when updating to a new Entity Framework Core release. 
444444    /// </summary> 
445445    protected  override  ShapedQueryExpression ?  TranslateAverage ( ShapedQueryExpression  source ,  LambdaExpression ?  selector ,  Type  resultType ) 
446-     { 
447-         var  selectExpression  =  ( SelectExpression ) source . QueryExpression ; 
448-         if  ( selectExpression . IsDistinct 
449-             ||  selectExpression . Limit  !=  null 
450-             ||  selectExpression . Offset  !=  null ) 
451-         { 
452-             return  null ; 
453-         } 
454- 
455-         if  ( selector  !=  null ) 
456-         { 
457-             source  =  TranslateSelect ( source ,  selector ) ; 
458-         } 
459- 
460-         var  projection  =  ( SqlExpression ) selectExpression . GetMappedProjection ( new  ProjectionMember ( ) ) ; 
461-         projection  =  _sqlExpressionFactory . Function ( "AVG" ,  new [ ]  {  projection  } ,  resultType ,  _typeMappingSource . FindMapping ( resultType ) ) ; 
462- 
463-         return  AggregateResultShaper ( source ,  projection ,  throwOnNullResult :  true ,  resultType ) ; 
464-     } 
446+         =>  TranslateAggregate ( source ,  selector ,  resultType ,  "AVG" ) ; 
465447
466448    /// <summary> 
467449    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to 
@@ -841,26 +823,7 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
841823    ///     doing so can result in application failures when updating to a new Entity Framework Core release. 
842824    /// </summary> 
843825    protected  override  ShapedQueryExpression ?  TranslateMax ( ShapedQueryExpression  source ,  LambdaExpression ?  selector ,  Type  resultType ) 
844-     { 
845-         var  selectExpression  =  ( SelectExpression ) source . QueryExpression ; 
846-         if  ( selectExpression . IsDistinct 
847-             ||  selectExpression . Limit  !=  null 
848-             ||  selectExpression . Offset  !=  null ) 
849-         { 
850-             return  null ; 
851-         } 
852- 
853-         if  ( selector  !=  null ) 
854-         { 
855-             source  =  TranslateSelect ( source ,  selector ) ; 
856-         } 
857- 
858-         var  projection  =  ( SqlExpression ) selectExpression . GetMappedProjection ( new  ProjectionMember ( ) ) ; 
859- 
860-         projection  =  _sqlExpressionFactory . Function ( "MAX" ,  new [ ]  {  projection  } ,  resultType ,  projection . TypeMapping ) ; 
861- 
862-         return  AggregateResultShaper ( source ,  projection ,  throwOnNullResult :  true ,  resultType ) ; 
863-     } 
826+         =>  TranslateAggregate ( source ,  selector ,  resultType ,  "MAX" ) ; 
864827
865828    /// <summary> 
866829    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to 
@@ -869,26 +832,7 @@ protected override ShapedQueryExpression TranslateCast(ShapedQueryExpression sou
869832    ///     doing so can result in application failures when updating to a new Entity Framework Core release. 
870833    /// </summary> 
871834    protected  override  ShapedQueryExpression ?  TranslateMin ( ShapedQueryExpression  source ,  LambdaExpression ?  selector ,  Type  resultType ) 
872-     { 
873-         var  selectExpression  =  ( SelectExpression ) source . QueryExpression ; 
874-         if  ( selectExpression . IsDistinct 
875-             ||  selectExpression . Limit  !=  null 
876-             ||  selectExpression . Offset  !=  null ) 
877-         { 
878-             return  null ; 
879-         } 
880- 
881-         if  ( selector  !=  null ) 
882-         { 
883-             source  =  TranslateSelect ( source ,  selector ) ; 
884-         } 
885- 
886-         var  projection  =  ( SqlExpression ) selectExpression . GetMappedProjection ( new  ProjectionMember ( ) ) ; 
887- 
888-         projection  =  _sqlExpressionFactory . Function ( "MIN" ,  new [ ]  {  projection  } ,  resultType ,  projection . TypeMapping ) ; 
889- 
890-         return  AggregateResultShaper ( source ,  projection ,  throwOnNullResult :  true ,  resultType ) ; 
891-     } 
835+     =>  TranslateAggregate ( source ,  selector ,  resultType ,  "MIN" ) ; 
892836
893837    /// <summary> 
894838    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to 
@@ -1241,7 +1185,7 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
12411185
12421186        projection  =  _sqlExpressionFactory . Function ( "SUM" ,  new [ ]  {  projection  } ,  serverOutputType ,  projection . TypeMapping ) ; 
12431187
1244-         return  AggregateResultShaper ( source ,  projection ,  throwOnNullResult :   false ,   resultType ) ; 
1188+         return  AggregateResultShaper ( source ,  projection ,  resultType ) ; 
12451189    } 
12461190
12471191    /// <summary> 
@@ -1515,6 +1459,35 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
15151459
15161460    #endregion Queryable collection support
15171461
1462+     private  ShapedQueryExpression ?  TranslateAggregate ( ShapedQueryExpression  source ,  LambdaExpression ?  selector ,  Type  resultType ,  string  functionName ) 
1463+     { 
1464+         var  selectExpression  =  ( SelectExpression ) source . QueryExpression ; 
1465+         if  ( selectExpression . IsDistinct 
1466+             ||  selectExpression . Limit  !=  null 
1467+             ||  selectExpression . Offset  !=  null ) 
1468+         { 
1469+             return  null ; 
1470+         } 
1471+ 
1472+         if  ( selector  !=  null ) 
1473+         { 
1474+             source  =  TranslateSelect ( source ,  selector ) ; 
1475+         } 
1476+ 
1477+         if  ( ! _subquery  &&  resultType . IsNullableType ( ) ) 
1478+         { 
1479+             // For nullable types, we want to return null from Max, Min, and Average, rather than throwing. See Issue #35094. 
1480+             // Note that relational databases typically return null, which propagates. Cosmos will instead return no elements, 
1481+             // and hence for Cosmos only we need to change no elements into null. 
1482+             source  =  source . UpdateResultCardinality ( ResultCardinality . SingleOrDefault ) ; 
1483+         } 
1484+ 
1485+         var  projection  =  ( SqlExpression ) selectExpression . GetMappedProjection ( new  ProjectionMember ( ) ) ; 
1486+         projection  =  _sqlExpressionFactory . Function ( functionName ,  [ projection ] ,  resultType ,  _typeMappingSource . FindMapping ( resultType ) ) ; 
1487+ 
1488+         return  AggregateResultShaper ( source ,  projection ,  resultType ) ; 
1489+     } 
1490+ 
15181491    private  bool  TryApplyPredicate ( ShapedQueryExpression  source ,  LambdaExpression  predicate ) 
15191492    { 
15201493        var  select =  ( SelectExpression ) source . QueryExpression ; 
@@ -1695,7 +1668,6 @@ private Expression RemapLambdaBody(ShapedQueryExpression shapedQueryExpression,
16951668    private  static ShapedQueryExpression  AggregateResultShaper ( 
16961669        ShapedQueryExpression  source , 
16971670        Expression  projection , 
1698-         bool  throwOnNullResult , 
16991671        Type  resultType ) 
17001672    { 
17011673        var  selectExpression  =  ( SelectExpression ) source . QueryExpression ; 
@@ -1706,29 +1678,7 @@ private static ShapedQueryExpression AggregateResultShaper(
17061678        var  nullableResultType  =  resultType . MakeNullable ( ) ; 
17071679        Expression  shaper  =  new  ProjectionBindingExpression ( source . QueryExpression ,  new  ProjectionMember ( ) ,  nullableResultType ) ; 
17081680
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 ) 
1681+         if  ( resultType  !=  shaper . Type ) 
17321682        { 
17331683            shaper  =  Expression . Convert ( shaper ,  resultType ) ; 
17341684        } 
0 commit comments