@@ -265,7 +265,6 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
265
265
if ( translated == QueryCompilationContext . NotTranslatedExpression )
266
266
{
267
267
// Attempt to translate access into a primitive collection property (i.e. array column)
268
-
269
268
if ( _sqlTranslator . TryTranslatePropertyAccess ( methodCallExpression , out var translatedExpression , out var property )
270
269
&& property is IProperty { IsPrimitiveCollection : true } regularProperty
271
270
&& translatedExpression is SqlExpression sqlExpression )
@@ -570,35 +569,8 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s
570
569
}
571
570
572
571
// Pattern-match Contains over ValuesExpression, translating to simplified 'item IN (1, 2, 3)' with constant elements
573
- if ( source . QueryExpression is SelectExpression
574
- {
575
- Tables :
576
- [
577
- ValuesExpression
578
- {
579
- RowValues : [ { Values . Count : 2 } , ..] ,
580
- ColumnNames : [ ValuesOrderingColumnName , ValuesValueColumnName ]
581
- } valuesExpression
582
- ] ,
583
- Predicate : null ,
584
- GroupBy : [ ] ,
585
- Having : null ,
586
- IsDistinct : false ,
587
- Limit : null ,
588
- Offset : null ,
589
- // Note that in the context of Contains we don't care about orderings
590
- }
591
- // Make sure that the source projects the column from the ValuesExpression directly, i.e. no projection out with some expression
592
- && projection is ColumnExpression projectedColumn
593
- && projectedColumn . Table == valuesExpression )
572
+ if ( TryExtractBareInlineCollectionValues ( source , out var values ) )
594
573
{
595
- var values = new SqlExpression [ valuesExpression . RowValues . Count ] ;
596
- for ( var i = 0 ; i < values . Length ; i ++ )
597
- {
598
- // Skip the first value (_ord), which is irrelevant for Contains
599
- values [ i ] = valuesExpression . RowValues [ i ] . Values [ 1 ] ;
600
- }
601
-
602
574
var inExpression = _sqlExpressionFactory . In ( translatedItem , values ) ;
603
575
return source . Update ( _sqlExpressionFactory . Select ( inExpression ) , source . ShaperExpression ) ;
604
576
}
@@ -970,13 +942,19 @@ private SqlExpression CreateJoinPredicate(Expression outerKey, Expression innerK
970
942
971
943
/// <inheritdoc />
972
944
protected override ShapedQueryExpression ? TranslateMax ( ShapedQueryExpression source , LambdaExpression ? selector , Type resultType )
973
- => TranslateAggregateWithSelector (
974
- source , selector , t => QueryableMethods . MaxWithoutSelector . MakeGenericMethod ( t ) , throwWhenEmpty : true , resultType ) ;
945
+ => TryExtractBareInlineCollectionValues ( source , out var values )
946
+ && _sqlExpressionFactory . TryCreateGreatest ( values , resultType , out var greatestExpression )
947
+ ? source . Update ( _sqlExpressionFactory . Select ( greatestExpression ) , source . ShaperExpression )
948
+ : TranslateAggregateWithSelector (
949
+ source , selector , t => QueryableMethods . MaxWithoutSelector . MakeGenericMethod ( t ) , throwWhenEmpty : true , resultType ) ;
975
950
976
951
/// <inheritdoc />
977
952
protected override ShapedQueryExpression ? TranslateMin ( ShapedQueryExpression source , LambdaExpression ? selector , Type resultType )
978
- => TranslateAggregateWithSelector (
979
- source , selector , t => QueryableMethods . MinWithoutSelector . MakeGenericMethod ( t ) , throwWhenEmpty : true , resultType ) ;
953
+ => TryExtractBareInlineCollectionValues ( source , out var values )
954
+ && _sqlExpressionFactory . TryCreateLeast ( values , resultType , out var leastExpression )
955
+ ? source . Update ( _sqlExpressionFactory . Select ( leastExpression ) , source . ShaperExpression )
956
+ : TranslateAggregateWithSelector (
957
+ source , selector , t => QueryableMethods . MinWithoutSelector . MakeGenericMethod ( t ) , throwWhenEmpty : true , resultType ) ;
980
958
981
959
/// <inheritdoc />
982
960
protected override ShapedQueryExpression ? TranslateOfType ( ShapedQueryExpression source , Type resultType )
@@ -2612,6 +2590,46 @@ private bool TryGetProjection(ShapedQueryExpression shapedQueryExpression, [NotN
2612
2590
return false ;
2613
2591
}
2614
2592
2593
+ private bool TryExtractBareInlineCollectionValues ( ShapedQueryExpression shapedQuery , [ NotNullWhen ( true ) ] out SqlExpression [ ] ? values )
2594
+ {
2595
+ if ( TryGetProjection ( shapedQuery , out var projection )
2596
+ && shapedQuery . QueryExpression is SelectExpression
2597
+ {
2598
+ Tables :
2599
+ [
2600
+ ValuesExpression
2601
+ {
2602
+ RowValues : [ { Values . Count : 2 } , ..] ,
2603
+ ColumnNames : [ ValuesOrderingColumnName , ValuesValueColumnName ]
2604
+ } valuesExpression
2605
+ ] ,
2606
+ Predicate : null ,
2607
+ GroupBy : [ ] ,
2608
+ Having : null ,
2609
+ IsDistinct : false ,
2610
+ Limit : null ,
2611
+ Offset : null ,
2612
+ // Note that we assume ordering doesn't matter (Contains/Min/Max)
2613
+ }
2614
+ // Make sure that the source projects the column from the ValuesExpression directly, i.e. no projection out with some expression
2615
+ && projection is ColumnExpression projectedColumn
2616
+ && projectedColumn . Table == valuesExpression )
2617
+ {
2618
+ values = new SqlExpression [ valuesExpression . RowValues . Count ] ;
2619
+
2620
+ for ( var i = 0 ; i < values . Length ; i ++ )
2621
+ {
2622
+ // Skip the first value (_ord) - this function assumes ordering doesn't matter
2623
+ values [ i ] = valuesExpression . RowValues [ i ] . Values [ 1 ] ;
2624
+ }
2625
+
2626
+ return true ;
2627
+ }
2628
+
2629
+ values = null ;
2630
+ return false ;
2631
+ }
2632
+
2615
2633
/// <summary>
2616
2634
/// A visitor which scans an expression tree and attempts to find columns for which we were missing type mappings (projected out
2617
2635
/// of queryable constant/parameter), and those type mappings have been inferred.
0 commit comments