Skip to content

Commit b2767b2

Browse files
committed
NH-3874 - Fix NullReferenceException
If user was trying to remove or evict a collection which key is of IUserType when the ReturnedType property of the IUserType implementation returns a base type of an actually persisted type (eg. object) the MessageHelper.CollectionInfoString could throw an NullReferenceException due to incorrect type check.
1 parent fad699d commit b2767b2

File tree

8 files changed

+192
-2
lines changed

8 files changed

+192
-2
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.NH3874
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
object _id;
10+
11+
protected override void OnSetUp()
12+
{
13+
using (var session = OpenSession())
14+
using (var tx = session.BeginTransaction())
15+
{
16+
var one = new One();
17+
var two = new Two { One = one };
18+
two.One.Twos = new[] { two };
19+
_id = session.Save(one);
20+
session.Save(two);
21+
22+
tx.Commit();
23+
}
24+
}
25+
26+
[Test]
27+
public void EvictShallNotThrowWhenLoggingIsEnabled()
28+
{
29+
using (var session = OpenSession())
30+
using (session.BeginTransaction())
31+
{
32+
var one = session.Get<One>(_id);
33+
34+
session.Evict(one);
35+
}
36+
}
37+
38+
protected override void OnTearDown()
39+
{
40+
using (var session = OpenSession())
41+
using (var tx = session.BeginTransaction())
42+
{
43+
session.Delete("from Two");
44+
session.Delete("from One");
45+
46+
tx.Commit();
47+
}
48+
}
49+
}
50+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace NHibernate.Test.NHSpecificTest.NH3874
2+
{
3+
public class IntWrapper
4+
{
5+
public IntWrapper(int id)
6+
{
7+
Id = id;
8+
}
9+
10+
public int Id { get; set; }
11+
}
12+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Data;
3+
using NHibernate.SqlTypes;
4+
using NHibernate.Type;
5+
using NHibernate.UserTypes;
6+
7+
namespace NHibernate.Test.NHSpecificTest.NH3874
8+
{
9+
public class IntWrapperType : IUserType
10+
{
11+
public SqlType[] SqlTypes
12+
{
13+
get { return new[] { NHNullableType.SqlType }; }
14+
}
15+
16+
public System.Type ReturnedType { get { return typeof(object); } }
17+
18+
public new bool Equals(object x, object y)
19+
{
20+
if (ReferenceEquals(x, y)) return true;
21+
if (x == null || y == null) return false;
22+
return x.Equals(y);
23+
}
24+
25+
public object DeepCopy(object value) { return value; }
26+
27+
public bool IsMutable { get { return false; } }
28+
29+
protected NullableType NHNullableType
30+
{
31+
get { return NHibernateUtil.Int32; }
32+
}
33+
34+
public object NullSafeGet(IDataReader dr, string[] names, object owner)
35+
{
36+
object obj = NHNullableType.NullSafeGet(dr, names[0]);
37+
if (obj == null) return null;
38+
return new IntWrapper((int)obj);
39+
}
40+
41+
public void NullSafeSet(IDbCommand cmd, object obj, int index)
42+
{
43+
if (obj == null)
44+
{
45+
((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
46+
}
47+
else
48+
{
49+
IntWrapper id = (IntWrapper)obj;
50+
((IDataParameter)cmd.Parameters[index]).Value = id.Id;
51+
}
52+
}
53+
54+
public int GetHashCode(object x)
55+
{
56+
return x.GetHashCode();
57+
}
58+
59+
public object Replace(object original, object target, object owner)
60+
{
61+
return original;
62+
}
63+
64+
public object Assemble(object cached, object owner)
65+
{
66+
return cached;
67+
}
68+
69+
public object Disassemble(object value)
70+
{
71+
return value;
72+
}
73+
}
74+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
assembly="NHibernate.Test"
4+
namespace="NHibernate.Test.NHSpecificTest.NH3874"
5+
default-lazy="false">
6+
7+
<class name="One" lazy="true">
8+
<id name="Id" column="Zzzz" type="IntWrapperType">
9+
<generator class="identity"/>
10+
</id>
11+
12+
<bag name="Twos" cascade="all-delete-orphan" inverse="true" lazy="true">
13+
<key column="WeirdId"/>
14+
<one-to-many class="Two"/>
15+
</bag>
16+
</class>
17+
18+
<class name="Two" lazy="true">
19+
<id name="Id" column="WeirdId" type="IntWrapperType">
20+
<generator class="foreign">
21+
<param name="property">One</param>
22+
</generator>
23+
</id>
24+
25+
<one-to-one name="One" class="One" constrained="true"/>
26+
</class>
27+
28+
</hibernate-mapping>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH3874
4+
{
5+
public class One
6+
{
7+
public virtual IntWrapper Id { get; set; }
8+
9+
public virtual IList<Two> Twos { get; set; }
10+
}
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace NHibernate.Test.NHSpecificTest.NH3874
2+
{
3+
public class Two
4+
{
5+
public virtual IntWrapper Id { get; set; }
6+
7+
public virtual One One { get; set; }
8+
}
9+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,11 @@
896896
<Compile Include="NHSpecificTest\NH3844\Fixture.cs" />
897897
<Compile Include="NHSpecificTest\NH3818\Fixture.cs" />
898898
<Compile Include="NHSpecificTest\NH3818\MyLovelyCat.cs" />
899+
<Compile Include="NHSpecificTest\NH3874\Fixture.cs" />
900+
<Compile Include="NHSpecificTest\NH3874\IntWrapper.cs" />
901+
<Compile Include="NHSpecificTest\NH3874\IntWrapperType.cs" />
902+
<Compile Include="NHSpecificTest\NH3874\One.cs" />
903+
<Compile Include="NHSpecificTest\NH3874\Two.cs" />
899904
<Compile Include="NHSpecificTest\NH646\Domain.cs" />
900905
<Compile Include="NHSpecificTest\NH646\Fixture.cs" />
901906
<Compile Include="NHSpecificTest\NH3234\Fixture.cs" />
@@ -3169,6 +3174,7 @@
31693174
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
31703175
</ItemGroup>
31713176
<ItemGroup>
3177+
<EmbeddedResource Include="NHSpecificTest\NH3874\Mappings.hbm.xml" />
31723178
<EmbeddedResource Include="NHSpecificTest\NH2218\Mappings.hbm.xml" />
31733179
<EmbeddedResource Include="NHSpecificTest\NH3046\Mappings.hbm.xml" />
31743180
<EmbeddedResource Include="NHSpecificTest\NH3518\Mappings.hbm.xml" />

src/NHibernate/Impl/MessageHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ internal static String CollectionInfoString(ICollectionPersister persister, IPer
297297
object ownerKey;
298298
// TODO: Is it redundant to attempt to use the collectionKey,
299299
// or is always using the owner id sufficient?
300-
if (collectionKey.GetType().IsAssignableFrom(ownerIdentifierType.ReturnedClass))
300+
if (ownerIdentifierType.ReturnedClass.IsInstanceOfType(collectionKey))
301301
{
302302
ownerKey = collectionKey;
303303
}
@@ -369,7 +369,7 @@ private static void AddIdToCollectionInfoString(ICollectionPersister persister,
369369
// the given ID. Due to property-ref keys, the collection key
370370
// may not be the owner key.
371371
IType ownerIdentifierType = persister.OwnerEntityPersister.IdentifierType;
372-
if (id.GetType().IsAssignableFrom(ownerIdentifierType.ReturnedClass))
372+
if (ownerIdentifierType.ReturnedClass.IsInstanceOfType(id))
373373
{
374374
s.Append(ownerIdentifierType.ToLoggableString(id, factory));
375375
}

0 commit comments

Comments
 (0)