@@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
1111/// any release. You should only use it directly in your code with extreme caution and knowing that
1212/// doing so can result in application failures when updating to a new Entity Framework Core release.
1313/// </summary>
14- public class SqlServerAggregateFunctionExpression : SqlFunctionExpression , IEquatable < SqlServerAggregateFunctionExpression >
14+ public class SqlServerAggregateFunctionExpression : SqlExpression , IEquatable < SqlServerAggregateFunctionExpression >
1515{
1616 /// <summary>
1717 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -20,15 +20,31 @@ public class SqlServerAggregateFunctionExpression : SqlFunctionExpression, IEqua
2020 /// doing so can result in application failures when updating to a new Entity Framework Core release.
2121 /// </summary>
2222 public SqlServerAggregateFunctionExpression (
23- string functionName ,
24- IEnumerable < SqlExpression > arguments ,
23+ string name ,
24+ IReadOnlyList < SqlExpression > arguments ,
2525 IReadOnlyList < OrderingExpression > orderings ,
2626 bool nullable ,
2727 IEnumerable < bool > argumentsPropagateNullability ,
2828 Type type ,
2929 RelationalTypeMapping ? typeMapping )
30- : base ( functionName , arguments , nullable , argumentsPropagateNullability , type , typeMapping )
31- => Orderings = orderings ;
30+ : base ( type , typeMapping )
31+ {
32+ Name = name ;
33+ Arguments = arguments . ToList ( ) ;
34+ Orderings = orderings ;
35+ IsNullable = nullable ;
36+ ArgumentsPropagateNullability = argumentsPropagateNullability . ToList ( ) ;
37+ }
38+
39+ /// <summary>
40+ /// The name of the function.
41+ /// </summary>
42+ public virtual string Name { get ; }
43+
44+ /// <summary>
45+ /// The list of arguments of this function.
46+ /// </summary>
47+ public virtual IReadOnlyList < SqlExpression > Arguments { get ; }
3248
3349 /// <summary>
3450 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -38,6 +54,16 @@ public SqlServerAggregateFunctionExpression(
3854 /// </summary>
3955 public virtual IReadOnlyList < OrderingExpression > Orderings { get ; }
4056
57+ /// <summary>
58+ /// A bool value indicating if the function can return null result.
59+ /// </summary>
60+ public virtual bool IsNullable { get ; }
61+
62+ /// <summary>
63+ /// A list of bool values indicating whether individual argument propagate null to the result.
64+ /// </summary>
65+ public virtual IReadOnlyList < bool > ArgumentsPropagateNullability { get ; }
66+
4167 /// <summary>
4268 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
4369 /// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -46,54 +72,70 @@ public SqlServerAggregateFunctionExpression(
4672 /// </summary>
4773 protected override Expression VisitChildren ( ExpressionVisitor visitor )
4874 {
49- var visitedBase = ( SqlFunctionExpression ) base . VisitChildren ( visitor ) ;
75+ SqlExpression [ ] ? arguments = null ;
76+ for ( var i = 0 ; i < Arguments . Count ; i ++ )
77+ {
78+ var visitedArgument = ( SqlExpression ) visitor . Visit ( Arguments [ i ] ) ;
79+ if ( visitedArgument != Arguments [ i ] && arguments is null )
80+ {
81+ arguments = new SqlExpression [ Arguments . Count ] ;
82+
83+ for ( var j = 0 ; j < i ; j ++ )
84+ {
85+ arguments [ j ] = Arguments [ j ] ;
86+ }
87+ }
5088
51- OrderingExpression [ ] ? visitedAggregateOrderings = null ;
89+ if ( arguments is not null )
90+ {
91+ arguments [ i ] = visitedArgument ;
92+ }
93+ }
5294
95+ OrderingExpression [ ] ? orderings = null ;
5396 for ( var i = 0 ; i < Orderings . Count ; i ++ )
5497 {
5598 var visitedOrdering = ( OrderingExpression ) visitor . Visit ( Orderings [ i ] ) ;
56- if ( visitedOrdering != Orderings [ i ] && visitedAggregateOrderings is null )
99+ if ( visitedOrdering != Orderings [ i ] && orderings is null )
57100 {
58- visitedAggregateOrderings = new OrderingExpression [ Orderings . Count ] ;
101+ orderings = new OrderingExpression [ Orderings . Count ] ;
59102
60- for ( var j = 0 ; j < visitedAggregateOrderings . Length ; j ++ )
103+ for ( var j = 0 ; j < i ; j ++ )
61104 {
62- visitedAggregateOrderings [ j ] = Orderings [ j ] ;
105+ orderings [ j ] = Orderings [ j ] ;
63106 }
64107 }
65108
66- if ( visitedAggregateOrderings is not null )
109+ if ( orderings is not null )
67110 {
68- visitedAggregateOrderings [ i ] = visitedOrdering ;
111+ orderings [ i ] = visitedOrdering ;
69112 }
70113 }
71114
72- return visitedBase != this || visitedAggregateOrderings is not null
115+ return arguments is not null || orderings is not null
73116 ? new SqlServerAggregateFunctionExpression (
74117 Name ,
75- visitedBase . Arguments ! ,
76- visitedAggregateOrderings ?? Orderings ,
118+ arguments ?? Arguments ,
119+ orderings ?? Orderings ,
77120 IsNullable ,
78- ArgumentsPropagateNullability ! ,
121+ ArgumentsPropagateNullability ,
79122 Type ,
80123 TypeMapping )
81124 : this ;
82125 }
83126
84127 /// <summary>
85- /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
86- /// the same compatibility standards as public APIs. It may be changed or removed without notice in
87- /// any release. You should only use it directly in your code with extreme caution and knowing that
88- /// doing so can result in application failures when updating to a new Entity Framework Core release.
128+ /// Applies supplied type mapping to this expression.
89129 /// </summary>
90- public override SqlServerAggregateFunctionExpression ApplyTypeMapping ( RelationalTypeMapping ? typeMapping )
130+ /// <param name="typeMapping">A relational type mapping to apply.</param>
131+ /// <returns>A new expression which has supplied type mapping.</returns>
132+ public virtual SqlServerAggregateFunctionExpression ApplyTypeMapping ( RelationalTypeMapping ? typeMapping )
91133 => new (
92134 Name ,
93- Arguments ! ,
135+ Arguments ,
94136 Orderings ,
95137 IsNullable ,
96- ArgumentsPropagateNullability ! ,
138+ ArgumentsPropagateNullability ,
97139 Type ,
98140 typeMapping ?? TypeMapping ) ;
99141
@@ -103,33 +145,29 @@ public override SqlServerAggregateFunctionExpression ApplyTypeMapping(Relational
103145 /// any release. You should only use it directly in your code with extreme caution and knowing that
104146 /// doing so can result in application failures when updating to a new Entity Framework Core release.
105147 /// </summary>
106- public override SqlFunctionExpression Update ( SqlExpression ? instance , IReadOnlyList < SqlExpression > ? arguments )
107- {
108- Check . DebugAssert ( arguments is not null , "arguments is not null" ) ;
109- Check . DebugAssert ( instance is null , "instance not supported on SqlServerFunctionExpression" ) ;
110-
111- return arguments . SequenceEqual ( Arguments ! )
112- ? this
113- : new SqlServerAggregateFunctionExpression (
114- Name , arguments , Orderings , IsNullable , ArgumentsPropagateNullability ! , Type , TypeMapping ) ;
115- }
116-
117- /// <summary>
118- /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
119- /// the same compatibility standards as public APIs. It may be changed or removed without notice in
120- /// any release. You should only use it directly in your code with extreme caution and knowing that
121- /// doing so can result in application failures when updating to a new Entity Framework Core release.
122- /// </summary>
123- public virtual SqlFunctionExpression UpdateOrderings ( IReadOnlyList < OrderingExpression > orderings )
124- => orderings == Orderings || orderings . SequenceEqual ( Orderings )
148+ public virtual SqlServerAggregateFunctionExpression Update (
149+ IReadOnlyList < SqlExpression > arguments ,
150+ IReadOnlyList < OrderingExpression > orderings )
151+ => ( ReferenceEquals ( arguments , Arguments ) || arguments . SequenceEqual ( Arguments ) )
152+ && ( ReferenceEquals ( orderings , Orderings ) || orderings . SequenceEqual ( Orderings ) )
125153 ? this
126154 : new SqlServerAggregateFunctionExpression (
127- Name , Arguments ! , orderings , IsNullable , ArgumentsPropagateNullability ! , Type , TypeMapping ) ;
155+ Name ,
156+ arguments ,
157+ orderings ,
158+ IsNullable ,
159+ ArgumentsPropagateNullability ,
160+ Type ,
161+ TypeMapping ) ;
128162
129163 /// <inheritdoc />
130164 protected override void Print ( ExpressionPrinter expressionPrinter )
131165 {
132- base . Print ( expressionPrinter ) ;
166+ expressionPrinter . Append ( Name ) ;
167+
168+ expressionPrinter . Append ( "(" ) ;
169+ expressionPrinter . VisitCollection ( Arguments ) ;
170+ expressionPrinter . Append ( ")" ) ;
133171
134172 if ( Orderings . Count > 0 )
135173 {
@@ -146,18 +184,27 @@ public override bool Equals(object? obj)
146184 /// <inheritdoc />
147185 public virtual bool Equals ( SqlServerAggregateFunctionExpression ? other )
148186 => ReferenceEquals ( this , other )
149- || base . Equals ( other ) && Orderings . SequenceEqual ( other . Orderings ) ;
187+ || other is not null
188+ && base . Equals ( other )
189+ && Name == other . Name
190+ && Arguments . SequenceEqual ( other . Arguments )
191+ && Orderings . SequenceEqual ( other . Orderings ) ;
150192
151193 /// <inheritdoc />
152194 public override int GetHashCode ( )
153195 {
154196 var hash = new HashCode ( ) ;
155-
156197 hash . Add ( base . GetHashCode ( ) ) ;
198+ hash . Add ( Name ) ;
199+
200+ for ( var i = 0 ; i < Arguments . Count ; i ++ )
201+ {
202+ hash . Add ( Arguments [ i ] ) ;
203+ }
157204
158- foreach ( var orderingExpression in Orderings )
205+ for ( var i = 0 ; i < Orderings . Count ; i ++ )
159206 {
160- hash . Add ( orderingExpression ) ;
207+ hash . Add ( Orderings [ i ] ) ;
161208 }
162209
163210 return hash . ToHashCode ( ) ;
0 commit comments