diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayArrayTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayArrayTypeMapping.cs index 99ae90349..8a2607308 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayArrayTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayArrayTypeMapping.cs @@ -137,11 +137,20 @@ private static bool Compare(TElem[]? a, TElem[]? b, ValueComparer element return false; } + if (ReferenceEquals(a, b)) + { + return true; + } + // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) for (var i = 0; i < a.Length; i++) + { if (!elementComparer.Equals(a[i], b[i])) + { return false; + } + } return true; } @@ -149,22 +158,29 @@ private static bool Compare(TElem[]? a, TElem[]? b, ValueComparer element private static int GetHashCode(TElem[] source, ValueComparer elementComparer) { var hash = new HashCode(); + foreach (var el in source) + { hash.Add(el, elementComparer); + } + return hash.ToHashCode(); } [return: NotNullIfNotNull("source")] private static TElem[]? Snapshot(TElem[]? source, ValueComparer elementComparer) { - if (source == null) + if (source is null) return null; var snapshot = new TElem[source.Length]; // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) for (var i = 0; i < source.Length; i++) + { snapshot[i] = elementComparer.Snapshot(source[i])!; // TODO: https://github.com/dotnet/efcore/pull/24410 + } + return snapshot; } } @@ -191,6 +207,11 @@ private static bool Compare(TElem?[]? a, TElem?[]? b, ValueComparer eleme return false; } + if (ReferenceEquals(a, b)) + { + return true; + } + // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) for (var i = 0; i < a.Length; i++) @@ -199,11 +220,17 @@ private static bool Compare(TElem?[]? a, TElem?[]? b, ValueComparer eleme if (el1 is null) { if (el2 is null) + { continue; + } + return false; } + if (el2 is null || !elementComparer.Equals(el1, el2)) + { return false; + } } return true; @@ -213,22 +240,31 @@ private static int GetHashCode(TElem?[] source, ValueComparer elementComp { var nullableEqualityComparer = new NullableEqualityComparer(elementComparer); var hash = new HashCode(); + foreach (var el in source) + { hash.Add(el, nullableEqualityComparer); + } + return hash.ToHashCode(); } [return: NotNullIfNotNull("source")] private static TElem?[]? Snapshot(TElem?[]? source, ValueComparer elementComparer) { - if (source == null) + if (source is null) + { return null; + } var snapshot = new TElem?[source.Length]; // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) for (var i = 0; i < source.Length; i++) - snapshot[i] = source[i] is { } value ? elementComparer.Snapshot(value) : (TElem?)null; + { + snapshot[i] = source[i] is { } value ? elementComparer.Snapshot(value) : null; + } + return snapshot; } } diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayListTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayListTypeMapping.cs index da79c8fca..cdc518033 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayListTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlArrayListTypeMapping.cs @@ -135,11 +135,20 @@ private static bool Compare(List? a, List? b, ValueComparer return false; } + if (ReferenceEquals(a, b)) + { + return true; + } + // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) for (var i = 0; i < a.Count; i++) + { if (!elementComparer.Equals(a[i], b[i])) + { return false; + } + } return true; } @@ -147,22 +156,30 @@ private static bool Compare(List? a, List? b, ValueComparer private static int GetHashCode(List source, ValueComparer elementComparer) { var hash = new HashCode(); + foreach (var el in source) + { hash.Add(el, elementComparer); + } + return hash.ToHashCode(); } private static List? Snapshot(List? source, ValueComparer elementComparer) { - if (source == null) + if (source is null) + { return null; + } var snapshot = new List(source.Count); // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) foreach (var e in source) + { snapshot.Add(elementComparer.Snapshot(e)!); // TODO: https://github.com/dotnet/efcore/pull/24410 + } return snapshot; } @@ -191,6 +208,11 @@ private static bool Compare(List? a, List? b, ValueComparer? a, List? b, ValueComparer source, ValueComparer element { var nullableEqualityComparer = new NullableEqualityComparer(elementComparer); var hash = new HashCode(); + foreach (var el in source) + { hash.Add(el, nullableEqualityComparer); + } + return hash.ToHashCode(); } private static List? Snapshot(List? source, ValueComparer elementComparer) { if (source == null) + { return null; + } var snapshot = new List(source.Count); // Note: the following currently boxes every element access because ValueComparer isn't really // generic (see https://github.com/aspnet/EntityFrameworkCore/issues/11072) foreach (var e in source) - snapshot.Add(e is { } value ? elementComparer.Snapshot(value) : (TElem?)null); + { + snapshot.Add(e is { } value ? elementComparer.Snapshot(value) : null); + } return snapshot; }