Skip to content

Commit 9fd9d4b

Browse files
NH-3981 - maps equality fix, collection helper cleanup.
1 parent 24717d6 commit 9fd9d4b

File tree

12 files changed

+370
-98
lines changed

12 files changed

+370
-98
lines changed

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,7 @@
14391439
<Compile Include="Unionsubclass\DatabaseKeyword.cs" />
14401440
<Compile Include="Unionsubclass\DatabaseKeywordBase.cs" />
14411441
<Compile Include="Unionsubclass\DatabaseKeywordsFixture.cs" />
1442+
<Compile Include="UtilityTest\CollectionHelperFixture.cs" />
14421443
<Compile Include="UtilityTest\ArrayHelperTests.cs" />
14431444
<Compile Include="UnionsubclassPolymorphicFormula\Company.cs" />
14441445
<Compile Include="UnionsubclassPolymorphicFormula\Party.cs" />
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
using System.Collections.Generic;
2+
using NHibernate.Util;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.UtilityTest
6+
{
7+
[TestFixture]
8+
public class CollectionHelperFixture
9+
{
10+
#region Bag
11+
12+
[Test]
13+
public void BagComparedToSelfShouldBeEqual()
14+
{
15+
var c1 = new List<string> { "1", "2", "3", "4" };
16+
Assert.That(CollectionHelper.BagEquals(c1, c1), Is.True);
17+
}
18+
19+
[Test]
20+
public void BagComparedToNullShouldBeInequal()
21+
{
22+
var c1 = new List<string> { "1", "2", "3", "4" };
23+
Assert.That(CollectionHelper.BagEquals(c1, null), Is.False);
24+
Assert.That(CollectionHelper.BagEquals(null, c1), Is.False);
25+
}
26+
27+
[Test]
28+
public void BagNullComparedToNullShouldBeEqual()
29+
{
30+
Assert.That(CollectionHelper.BagEquals<string>(null, null), Is.True);
31+
}
32+
33+
[Test]
34+
public void BagsWithSameContentShouldBeEqual()
35+
{
36+
var c1 = new List<string> { "1", "2", "3", "4", "2" };
37+
var c2 = new List<string> { "1", "2", "3", "4", "2" };
38+
Assert.That(CollectionHelper.BagEquals(c1, c2), Is.True);
39+
}
40+
41+
[Test]
42+
public void BagsWithSameCountButDistinctValuesShouldBeInequal()
43+
{
44+
var c1 = new List<string> { "1", "2", "3", "4" };
45+
var c2 = new List<string> { "1", "2", "3", "3" };
46+
Assert.That(CollectionHelper.BagEquals(c1, c2), Is.False);
47+
}
48+
49+
[Test]
50+
public void BagsWithSameElementsButDistinctOrderShouldBeEqual()
51+
{
52+
var c1 = new List<string> { "1", "2", "3", "4", "2" };
53+
var c2 = new List<string> { "2", "1", "2", "4", "3" };
54+
Assert.That(CollectionHelper.BagEquals(c1, c2), Is.True);
55+
}
56+
57+
[Test]
58+
public void BagsWithoutSameCountShouldBeInequal()
59+
{
60+
var c1 = new List<string> { "1", "2", "2", "1" };
61+
var c2 = new List<string> { "1", "2" };
62+
Assert.That(CollectionHelper.BagEquals(c1, c2), Is.False);
63+
Assert.That(CollectionHelper.BagEquals(c2, c1), Is.False);
64+
}
65+
66+
#endregion
67+
68+
#region Dictionary/Map
69+
70+
[Test]
71+
public void MapComparedToSelfShouldBeEqual()
72+
{
73+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
74+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, d1), Is.True);
75+
}
76+
77+
[Test]
78+
public void MapComparedToNullShouldBeInequal()
79+
{
80+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
81+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, null), Is.False);
82+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(null, d1), Is.False);
83+
}
84+
85+
[Test]
86+
public void MapNullComparedToNullShouldBeEqual()
87+
{
88+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(null, null), Is.True);
89+
}
90+
91+
[Test]
92+
public void MapsWithSameContentShouldBeEqual()
93+
{
94+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
95+
var d2 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
96+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, d2), Is.True);
97+
}
98+
99+
// Fails till NH-3981 is fixed.
100+
[Test]
101+
public void MapsWithSameCountButDistinctKeysShouldBeInequal()
102+
{
103+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
104+
var d2 = new Dictionary<string, string> { { "1", "2" }, { "4", "3" } };
105+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, d2), Is.False);
106+
}
107+
108+
[Test]
109+
public void MapsWithSameCountButDistinctValuesShouldBeInequal()
110+
{
111+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
112+
var d2 = new Dictionary<string, string> { { "1", "2" }, { "3", "3" } };
113+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, d2), Is.False);
114+
}
115+
116+
[Test]
117+
public void MapsWithoutSameCountShouldBeInequal()
118+
{
119+
var d1 = new Dictionary<string, string> { { "1", "2" }, { "3", "4" } };
120+
var d2 = new Dictionary<string, string> { { "1", "2" } };
121+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d1, d2), Is.False);
122+
Assert.That(CollectionHelper.DictionaryEquals<string, string>(d2, d1), Is.False);
123+
}
124+
125+
#endregion
126+
127+
#region Set
128+
129+
[Test]
130+
public void SetComparedToSelfShouldBeEqual()
131+
{
132+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
133+
Assert.That(CollectionHelper.SetEquals(c1, c1), Is.True);
134+
}
135+
136+
[Test]
137+
public void SetComparedToNullShouldBeInequal()
138+
{
139+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
140+
Assert.That(CollectionHelper.SetEquals(c1, null), Is.False);
141+
Assert.That(CollectionHelper.SetEquals(null, c1), Is.False);
142+
}
143+
144+
[Test]
145+
public void SetNullComparedToNullShouldBeEqual()
146+
{
147+
Assert.That(CollectionHelper.SetEquals<string>(null, null), Is.True);
148+
}
149+
150+
[Test]
151+
public void SetsWithSameContentShouldBeEqual()
152+
{
153+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
154+
var c2 = new HashSet<string> { "1", "2", "3", "4" };
155+
Assert.That(CollectionHelper.SetEquals(c1, c2), Is.True);
156+
}
157+
158+
[Test]
159+
public void SetsWithSameCountButDistinctValuesShouldBeInequal()
160+
{
161+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
162+
var c2 = new HashSet<string> { "1", "2", "3", "5" };
163+
Assert.That(CollectionHelper.SetEquals(c1, c2), Is.False);
164+
}
165+
166+
[Test]
167+
public void SetsWithSameElementsButDistinctOrderShouldBeEqual()
168+
{
169+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
170+
var c2 = new HashSet<string> { "1", "2", "4", "3" };
171+
Assert.That(CollectionHelper.SetEquals(c1, c2), Is.True);
172+
}
173+
174+
[Test]
175+
public void SetsWithoutSameCountShouldBeInequal()
176+
{
177+
var c1 = new HashSet<string> { "1", "2", "3", "4" };
178+
var c2 = new HashSet<string> { "1", "2" };
179+
Assert.That(CollectionHelper.SetEquals(c1, c2), Is.False);
180+
Assert.That(CollectionHelper.SetEquals(c2, c1), Is.False);
181+
}
182+
183+
#endregion
184+
185+
#region List/Sequence
186+
187+
[Test]
188+
public void SequenceComparedToSelfShouldBeEqual()
189+
{
190+
var c1 = new List<string> { "1", "2", "3", "4" };
191+
Assert.That(CollectionHelper.SequenceEquals(c1, c1), Is.True);
192+
}
193+
194+
[Test]
195+
public void SequenceComparedToNullShouldBeInequal()
196+
{
197+
var c1 = new List<string> { "1", "2", "3", "4" };
198+
Assert.That(CollectionHelper.SequenceEquals(c1, null), Is.False);
199+
Assert.That(CollectionHelper.SequenceEquals(null, c1), Is.False);
200+
}
201+
202+
[Test]
203+
public void SequenceNullComparedToNullShouldBeEqual()
204+
{
205+
Assert.That(CollectionHelper.SequenceEquals<string>(null, null), Is.True);
206+
}
207+
208+
[Test]
209+
public void SequencesWithSameContentShouldBeEqual()
210+
{
211+
var c1 = new List<string> { "1", "2", "3", "4" };
212+
var c2 = new List<string> { "1", "2", "3", "4" };
213+
Assert.That(CollectionHelper.SequenceEquals(c1, c2), Is.True);
214+
}
215+
216+
[Test]
217+
public void SequencesWithSameCountButDistinctValuesShouldBeInequal()
218+
{
219+
var c1 = new List<string> { "1", "2", "3", "4" };
220+
var c2 = new List<string> { "1", "2", "3", "3" };
221+
Assert.That(CollectionHelper.SequenceEquals(c1, c2), Is.False);
222+
}
223+
224+
[Test]
225+
public void SequencesWithSameElementsButDistinctOrderShouldBeInequal()
226+
{
227+
var c1 = new List<string> { "1", "2", "3", "4" };
228+
var c2 = new List<string> { "1", "2", "4", "3" };
229+
Assert.That(CollectionHelper.SequenceEquals(c1, c2), Is.False);
230+
}
231+
232+
[Test]
233+
public void SequencesWithoutSameCountShouldBeInequal()
234+
{
235+
var c1 = new List<string> { "1", "2", "3", "4" };
236+
var c2 = new List<string> { "1", "2" };
237+
Assert.That(CollectionHelper.SequenceEquals(c1, c2), Is.False);
238+
Assert.That(CollectionHelper.SequenceEquals(c2, c1), Is.False);
239+
}
240+
241+
#endregion
242+
}
243+
}

src/NHibernate/Cache/QueryKey.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ public override bool Equals(object other)
137137
return false;
138138
}
139139

140-
if (!CollectionHelper.CollectionEquals<int>(_multiQueriesFirstRows, that._multiQueriesFirstRows))
140+
if (!CollectionHelper.SequenceEquals<int>(_multiQueriesFirstRows, that._multiQueriesFirstRows))
141141
{
142142
return false;
143143
}
144-
if (!CollectionHelper.CollectionEquals<int>(_multiQueriesMaxRows, that._multiQueriesMaxRows))
144+
if (!CollectionHelper.SequenceEquals<int>(_multiQueriesMaxRows, that._multiQueriesMaxRows))
145145
{
146146
return false;
147147
}

src/NHibernate/Collection/Generic/PersistentGenericList.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public override bool Equals(object obj)
230230
return false;
231231
}
232232
Read();
233-
return CollectionHelper.CollectionEquals(WrappedList, that);
233+
return CollectionHelper.SequenceEquals(WrappedList, that);
234234
}
235235

236236
public override int GetHashCode()

src/NHibernate/Collection/Generic/PersistentGenericMap.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ public override bool EqualsSnapshot(ICollectionPersister persister)
7272
}
7373
foreach (KeyValuePair<TKey, TValue> entry in WrappedMap)
7474
{
75-
if (elementType.IsDirty(entry.Value, xmap[entry.Key], Session))
75+
// This method is not currently called if a key has been removed/added, but better be on the safe side.
76+
if (!xmap.TryGetValue(entry.Key, out var value) ||
77+
elementType.IsDirty(value, entry.Value, Session))
7678
{
7779
return false;
7880
}

src/NHibernate/Engine/Query/Sql/NativeSQLQuerySpecification.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ public override bool Equals(object obj)
6565
// Code taken back from 8e92af3f and amended according to NH-1931.
6666
return hashCode == that.hashCode &&
6767
queryString.Equals(that.queryString) &&
68-
CollectionHelper.CollectionEquals(querySpaces, that.querySpaces) &&
69-
CollectionHelper.CollectionEquals<INativeSQLQueryReturn>(sqlQueryReturns, that.sqlQueryReturns);
68+
CollectionHelper.SequenceEquals(querySpaces, that.querySpaces) &&
69+
CollectionHelper.SequenceEquals<INativeSQLQueryReturn>(sqlQueryReturns, that.sqlQueryReturns);
7070
}
7171

7272
public override int GetHashCode()

src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ protected override bool IsDuplicateAssociation(string foreignKeyTable, string[]
2121
{
2222
//disable a join back to this same association
2323
bool isSameJoin = oneToManyPersister.TableName.Equals(foreignKeyTable)
24-
&& CollectionHelper.CollectionEquals<string>(foreignKeyColumns, oneToManyPersister.KeyColumnNames);
24+
&& CollectionHelper.SequenceEquals<string>(foreignKeyColumns, oneToManyPersister.KeyColumnNames);
2525
return isSameJoin || base.IsDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
2626
}
2727

src/NHibernate/Loader/JoinWalker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ public override bool Equals(object other)
573573
if (that == null)
574574
return false;
575575

576-
return that.table.Equals(table) && CollectionHelper.CollectionEquals<string>(columns, that.columns);
576+
return that.table.Equals(table) && CollectionHelper.SequenceEquals<string>(columns, that.columns);
577577
}
578578

579579
public override int GetHashCode()

src/NHibernate/Mapping/Table.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,8 +1031,8 @@ public bool Equals(ForeignKeyKey x, ForeignKeyKey y)
10311031
{
10321032
// NH : Different implementation to prevent NH930 (look test)
10331033
return //y.referencedClassName.Equals(x.referencedClassName) &&
1034-
CollectionHelper.CollectionEquals<Column>(y.columns, x.columns)
1035-
&& CollectionHelper.CollectionEquals<Column>(y.referencedColumns, x.referencedColumns);
1034+
CollectionHelper.SequenceEquals<Column>(y.columns, x.columns)
1035+
&& CollectionHelper.SequenceEquals<Column>(y.referencedColumns, x.referencedColumns);
10361036
}
10371037

10381038
public int GetHashCode(ForeignKeyKey obj)

src/NHibernate/Type/GenericBagType.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4-
using System.Linq;
54
using NHibernate.Collection;
65
using NHibernate.Collection.Generic;
76
using NHibernate.Engine;
87
using NHibernate.Persister.Collection;
8+
using NHibernate.Util;
99

1010
namespace NHibernate.Type
1111
{
@@ -75,11 +75,7 @@ public override object Instantiate(int anticipatedSize)
7575

7676
protected override bool AreCollectionElementsEqual(IEnumerable original, IEnumerable target)
7777
{
78-
var first = (IEnumerable<T>)original;
79-
var second = (IEnumerable<T>) target;
80-
81-
return first.Count() == second.Count() &&
82-
first.All(element => first.Count(x => x.Equals(element)) == second.Count(x => x.Equals(element)));
78+
return CollectionHelper.BagEquals((IEnumerable<T>)original, (IEnumerable<T>)target);
8379
}
8480
}
8581
}

src/NHibernate/Type/GenericIdentifierBagType.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using NHibernate.Collection.Generic;
77
using NHibernate.Engine;
88
using NHibernate.Persister.Collection;
9+
using NHibernate.Util;
910

1011
namespace NHibernate.Type
1112
{
@@ -85,15 +86,6 @@ protected override void Add(object collection, object element)
8586
((IList<T>)collection).Add((T)element);
8687
}
8788

88-
protected override bool AreCollectionElementsEqual(IEnumerable original, IEnumerable target)
89-
{
90-
var first = (IList<T>)original;
91-
var second = (IList<T>)target;
92-
93-
return first.Count == second.Count &&
94-
first.All(element => first.Count(x => x.Equals(element)) == second.Count(x => x.Equals(element)));
95-
}
96-
9789
public override object ReplaceElements(
9890
object original,
9991
object target,
@@ -153,5 +145,10 @@ public override object ReplaceElements(
153145

154146
return target;
155147
}
148+
149+
protected override bool AreCollectionElementsEqual(IEnumerable original, IEnumerable target)
150+
{
151+
return CollectionHelper.BagEquals((IEnumerable<T>)original, (IEnumerable<T>)target);
152+
}
156153
}
157154
}

0 commit comments

Comments
 (0)