Skip to content

Commit aa86ce5

Browse files
committed
SqlServerAggregateFunctionExpression no longer extends SqlFunctionExpression
1 parent aceae67 commit aa86ce5

File tree

6 files changed

+244
-147
lines changed

6 files changed

+244
-147
lines changed

src/EFCore.Relational/Query/SqlExpressions/SqlFunctionExpression.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ private SqlFunctionExpression(
250250
/// <summary>
251251
/// A list of bool values indicating whether individual argument propagate null to the result.
252252
/// </summary>
253-
254253
public virtual IReadOnlyList<bool>? ArgumentsPropagateNullability { get; }
255254

256255
/// <inheritdoc />

src/EFCore.SqlServer/Query/Internal/SqlServerAggregateFunctionExpression.cs

Lines changed: 96 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -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();

src/EFCore.SqlServer/Query/Internal/SqlServerExpression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static SqlFunctionExpression AggregateFunction(
4343
/// any release. You should only use it directly in your code with extreme caution and knowing that
4444
/// doing so can result in application failures when updating to a new Entity Framework Core release.
4545
/// </summary>
46-
public static SqlFunctionExpression AggregateFunctionWithOrdering(
46+
public static SqlExpression AggregateFunctionWithOrdering(
4747
ISqlExpressionFactory sqlExpressionFactory,
4848
string name,
4949
IEnumerable<SqlExpression> arguments,

0 commit comments

Comments
 (0)