Skip to content

Commit a2d3122

Browse files
Fix NRE with merge and ignore not-found (#2657)
Co-authored-by: Roman Artiukhin <[email protected]>
1 parent 1e27b45 commit a2d3122

File tree

7 files changed

+181
-8
lines changed

7 files changed

+181
-8
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NUnit.Framework;
13+
using NHibernate.Linq;
14+
15+
namespace NHibernate.Test.NHSpecificTest.GH2627
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnSetUp()
22+
{
23+
using (var session = OpenSession())
24+
using (var transaction = session.BeginTransaction())
25+
{
26+
var e1 = new Entity {Name = "Bob"};
27+
session.Save(e1);
28+
29+
transaction.Commit();
30+
}
31+
}
32+
33+
protected override void OnTearDown()
34+
{
35+
using (var session = OpenSession())
36+
using (var transaction = session.BeginTransaction())
37+
{
38+
session.CreateQuery("delete from Child").ExecuteUpdate();
39+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
40+
41+
transaction.Commit();
42+
}
43+
}
44+
45+
[Test]
46+
public async Task NullRefInMergeAsync()
47+
{
48+
Child child;
49+
using (var session = OpenSession())
50+
using (var t = session.BeginTransaction())
51+
{
52+
child = new Child
53+
{
54+
Parent = await (session.Query<Entity>().FirstOrDefaultAsync()),
55+
Name = "John"
56+
};
57+
58+
await (t.CommitAsync());
59+
}
60+
61+
using (var session = OpenSession())
62+
using (var t = session.BeginTransaction())
63+
{
64+
await (session.MergeAsync(child));
65+
await (t.CommitAsync());
66+
}
67+
}
68+
}
69+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2627
4+
{
5+
public class Child
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual Entity Parent { get; set; }
9+
public virtual string Name { get; set; }
10+
}
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2627
4+
{
5+
public class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH2627
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
protected override void OnSetUp()
10+
{
11+
using (var session = OpenSession())
12+
using (var transaction = session.BeginTransaction())
13+
{
14+
var e1 = new Entity {Name = "Bob"};
15+
session.Save(e1);
16+
17+
transaction.Commit();
18+
}
19+
}
20+
21+
protected override void OnTearDown()
22+
{
23+
using (var session = OpenSession())
24+
using (var transaction = session.BeginTransaction())
25+
{
26+
session.CreateQuery("delete from Child").ExecuteUpdate();
27+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
28+
29+
transaction.Commit();
30+
}
31+
}
32+
33+
[Test]
34+
public void NullRefInMerge()
35+
{
36+
Child child;
37+
using (var session = OpenSession())
38+
using (var t = session.BeginTransaction())
39+
{
40+
child = new Child
41+
{
42+
Parent = session.Query<Entity>().FirstOrDefault(),
43+
Name = "John"
44+
};
45+
46+
t.Commit();
47+
}
48+
49+
using (var session = OpenSession())
50+
using (var t = session.BeginTransaction())
51+
{
52+
session.Merge(child);
53+
t.Commit();
54+
}
55+
}
56+
}
57+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.GH2627">
4+
5+
<class name="Entity">
6+
<id name="Id" generator="guid.comb"/>
7+
<property name="Name"/>
8+
</class>
9+
10+
<class name="Child">
11+
<id name="Id" generator="guid.comb"/>
12+
<property name="Name"/>
13+
<many-to-one name="Parent" not-found="ignore"/>
14+
</class>
15+
16+
</hibernate-mapping>

src/NHibernate/Async/Type/ManyToOneType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
using System;
1212
using System.Data.Common;
1313
using NHibernate.Engine;
14-
using NHibernate.Persister.Entity;
14+
using NHibernate.Proxy;
1515
using NHibernate.SqlTypes;
1616
using NHibernate.Util;
1717

src/NHibernate/Type/ManyToOneType.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Data.Common;
33
using NHibernate.Engine;
4-
using NHibernate.Persister.Entity;
4+
using NHibernate.Proxy;
55
using NHibernate.SqlTypes;
66
using NHibernate.Util;
77

@@ -162,14 +162,24 @@ private bool IsIdentifier(object value, ISessionImplementor session)
162162

163163
public override bool IsNull(object owner, ISessionImplementor session)
164164
{
165-
if (IsNullable && !string.IsNullOrEmpty(PropertyName))
166-
{
167-
EntityEntry entry = session.PersistenceContext.GetEntry(owner);
165+
if (!IsNullable || string.IsNullOrEmpty(PropertyName) || owner == null)
166+
return false;
168167

169-
return session.PersistenceContext.IsPropertyNull(entry.EntityKey, PropertyName);
170-
}
168+
var entityKey = GetEntityKey(owner, session);
169+
if (entityKey == null)
170+
return false;
171171

172-
return false;
172+
return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
173+
}
174+
175+
private static EntityKey GetEntityKey(object owner, ISessionImplementor session)
176+
{
177+
var entry = session.PersistenceContext.GetEntry(owner);
178+
if (entry != null)
179+
return entry.EntityKey;
180+
if (owner is INHibernateProxy proxy)
181+
return session.GenerateEntityKey(proxy.HibernateLazyInitializer.Identifier, session.Factory.GetEntityPersister(proxy.HibernateLazyInitializer.EntityName));
182+
return null;
173183
}
174184

175185
public override object Disassemble(object value, ISessionImplementor session, object owner)

0 commit comments

Comments
 (0)