Skip to content

Commit

Permalink
Normalize .Count != 0 to Any() in preprocessing
Browse files Browse the repository at this point in the history
Closes #33644
  • Loading branch information
roji committed May 1, 2024
1 parent ebbc5ee commit bd44c94
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,47 @@ public virtual Expression Normalize(Expression expression)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected override Expression VisitBinary(BinaryExpression binaryExpression)
{
// Convert array[x] to array.ElementAt(x)
if (binaryExpression is
{
NodeType: ExpressionType.ArrayIndex,
Left: var source,
Right: var index
})
protected override Expression VisitBinary(BinaryExpression binaryExpression) =>
binaryExpression switch
{
return VisitMethodCall(
// Convert array[x] to array.ElementAt(x)
{ NodeType: ExpressionType.ArrayIndex, Left: var source, Right: var index }
=> VisitMethodCall(
Expression.Call(EnumerableMethods.ElementAt.MakeGenericMethod(source.Type.GetSequenceType()), source, index)),

// Convert x.Count > 0 and x.Count != 0 to x.Any()
{
NodeType: ExpressionType.GreaterThan or ExpressionType.NotEqual,
Left: MemberExpression
{
Member: { Name: nameof(ICollection<object>.Count), DeclaringType.IsGenericType: true } member,
Expression: Expression source
},
Right: ConstantExpression { Value: 0 }
}
when (member.DeclaringType.GetGenericTypeDefinition().GetInterfaces().Any(x => x.GetGenericTypeDefinition() == typeof(ICollection<>)))
=> VisitMethodCall(
Expression.Call(
EnumerableMethods.ElementAt.MakeGenericMethod(source.Type.GetSequenceType()), source, index));
}
EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()),
source)),

return base.VisitBinary(binaryExpression);
}
// Same for arrays: convert x.Length > 0 and x.Length != 0 to x.Any()
{
NodeType: ExpressionType.GreaterThan or ExpressionType.NotEqual,
Left: UnaryExpression
{
NodeType: ExpressionType.ArrayLength,
Operand: Expression source
},
Right: ConstantExpression { Value: 0 }
}
=> VisitMethodCall(
Expression.Call(
EnumerableMethods.AnyWithoutPredicate.MakeGenericMethod(source.Type.GetSequenceType()),
source)),

_ => base.VisitBinary(binaryExpression)
};

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,10 @@ public override async Task Collection_select_nav_prop_predicate(bool async)
AssertSql(
"""
SELECT CASE
WHEN (
SELECT COUNT(*)
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o]
WHERE [c].[CustomerID] = [o].[CustomerID]) > 0 THEN CAST(1 AS bit)
WHERE [c].[CustomerID] = [o].[CustomerID]) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
FROM [Customers] AS [c]
Expand Down

0 comments on commit bd44c94

Please sign in to comment.