Skip to content

Commit

Permalink
Perform structural equality in ExpressionEqualityComparer
Browse files Browse the repository at this point in the history
Fixes #28581
  • Loading branch information
roji committed Sep 7, 2022
1 parent 4bb67a7 commit a5a67c4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
24 changes: 20 additions & 4 deletions src/EFCore/Query/ExpressionEqualityComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// ReSharper disable ForCanBeConvertedToForeach
// ReSharper disable LoopCanBeConvertedToQuery

using System.Collections;

namespace Microsoft.EntityFrameworkCore.Query;

/// <summary>
Expand Down Expand Up @@ -64,10 +66,19 @@ public int GetHashCode(Expression obj)
break;

case ConstantExpression constantExpression:
if (constantExpression.Value != null
&& !(constantExpression.Value is IQueryable))
switch (constantExpression.Value)
{
hash.Add(constantExpression.Value);
case IQueryable:
case null:
break;

case IStructuralEquatable structuralEquatable:
hash.Add(structuralEquatable.GetHashCode(StructuralComparisons.StructuralEqualityComparer));
break;

default:
hash.Add(constantExpression.Value);
break;
}

break;
Expand Down Expand Up @@ -354,7 +365,12 @@ private bool CompareConditional(ConditionalExpression a, ConditionalExpression b
&& Compare(a.IfFalse, b.IfFalse);

private static bool CompareConstant(ConstantExpression a, ConstantExpression b)
=> Equals(a.Value, b.Value);
{
var (v1, v2) = (a.Value, b.Value);

return Equals(v1, v2)
|| (v1 is IStructuralEquatable array1 && array1.Equals(v2, StructuralComparisons.StructuralEqualityComparer));
}

private bool CompareGoto(GotoExpression a, GotoExpression b)
=> a.Kind == b.Kind
Expand Down
16 changes: 16 additions & 0 deletions test/EFCore.Tests/Query/ExpressionEqualityComparerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,22 @@ public void Index_expressions_are_compared_correctly()
Assert.True(expressionComparer.Equals(e2, e3));
}

[ConditionalFact]
public void Array_constant_expressions_are_compared_correctly()
{
var expressionComparer = ExpressionEqualityComparer.Instance;

var e1 = Expression.Constant(new[] { 1, 2, 3 });
var e2 = Expression.Constant(new[] { 1, 2, 3 });
var e3 = Expression.Constant(new[] { 1, 2, 4 });

Assert.True(expressionComparer.Equals(e1, e2));
Assert.False(expressionComparer.Equals(e1, e3));

Assert.Equal(expressionComparer.GetHashCode(e1), expressionComparer.GetHashCode(e2));
Assert.NotEqual(expressionComparer.GetHashCode(e1), expressionComparer.GetHashCode(e3));
}

private class Node
{
[UsedImplicitly]
Expand Down

0 comments on commit a5a67c4

Please sign in to comment.