Skip to content

Commit 1f3f430

Browse files
Port HHH-12826 and HHH-12846.
To be squashed.
1 parent a759f83 commit 1f3f430

File tree

8 files changed

+263
-6
lines changed

8 files changed

+263
-6
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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.GH1754
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnSetUp()
22+
{
23+
Sfi.Statistics.IsStatisticsEnabled = true;
24+
}
25+
26+
protected override void OnTearDown()
27+
{
28+
Sfi.Statistics.IsStatisticsEnabled = false;
29+
using (var session = OpenSession())
30+
using (var transaction = session.BeginTransaction())
31+
{
32+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
33+
34+
transaction.Commit();
35+
}
36+
}
37+
38+
[Test]
39+
public async Task PersistIdentityDoNotImmediateExecuteQueryAsync()
40+
{
41+
using (var session = OpenSession())
42+
{
43+
Sfi.Statistics.Clear();
44+
await (session.PersistAsync(new Entity {Name = "Test"}));
45+
46+
Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(0));
47+
48+
await (session.FlushAsync());
49+
50+
Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(1));
51+
}
52+
}
53+
54+
[Test]
55+
public async Task PersistIdentityDoNotSaveIfSessionIsNotFlushedAsync()
56+
{
57+
using (var session = OpenSession())
58+
{
59+
await (session.PersistAsync(new Entity {Name = "Test"}));
60+
}
61+
62+
using (var session = OpenSession())
63+
{
64+
var count = await (session.Query<Entity>().CountAsync());
65+
Assert.That(count, Is.EqualTo(0));
66+
}
67+
}
68+
69+
// https://hibernate.atlassian.net/browse/HHH-12826
70+
[Test]
71+
public async Task CanAddChildAfterFlushAsync()
72+
{
73+
using (var session = OpenSession())
74+
{
75+
var parent = new Entity { Name = "Parent" };
76+
var child = new Entity { Name = "Child" };
77+
using (var t = session.BeginTransaction())
78+
{
79+
await (session.PersistAsync(parent));
80+
await (session.FlushAsync());
81+
parent.Children.Add(child);
82+
await (t.CommitAsync());
83+
}
84+
85+
Assert.That(parent.Children, Has.Count.EqualTo(1));
86+
Assert.That(parent.Children, Does.Contain(child));
87+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
88+
}
89+
}
90+
91+
[Test]
92+
public async Task CanAddChildAfterFlushWithoutTransactionAsync()
93+
{
94+
using (var session = OpenSession())
95+
{
96+
var parent = new Entity { Name = "Parent" };
97+
var child = new Entity { Name = "Child" };
98+
await (session.PersistAsync(parent));
99+
await (session.FlushAsync());
100+
parent.Children.Add(child);
101+
await (session.FlushAsync());
102+
103+
Assert.That(parent.Children, Has.Count.EqualTo(1));
104+
Assert.That(parent.Children, Does.Contain(child));
105+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
106+
}
107+
}
108+
109+
// https://hibernate.atlassian.net/browse/HHH-12846
110+
[Test]
111+
public async Task CanMergeWithTransientChildAsync()
112+
{
113+
using (var session = OpenSession())
114+
{
115+
var parent = new Entity { Name = "Parent" };
116+
using (var t = session.BeginTransaction())
117+
{
118+
await (session.PersistAsync(parent));
119+
await (t.CommitAsync());
120+
}
121+
122+
var child = new Entity { Name = "Child" };
123+
using (var t = session.BeginTransaction())
124+
{
125+
parent.Children.Add(child);
126+
await (session.MergeAsync(parent));
127+
await (t.CommitAsync());
128+
}
129+
130+
Assert.That(parent.Children, Has.Count.EqualTo(1));
131+
// Merge should duplicate child and leave original instance un-associated with the session.
132+
Assert.That(parent.Children, Does.Not.Contain(child));
133+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
134+
}
135+
}
136+
137+
[Test]
138+
public async Task CanMergeWithTransientChildWithoutTransactionAsync()
139+
{
140+
using (var session = OpenSession())
141+
{
142+
var parent = new Entity { Name = "Parent" };
143+
await (session.PersistAsync(parent));
144+
await (session.FlushAsync());
145+
146+
var child = new Entity { Name = "Child" };
147+
parent.Children.Add(child);
148+
await (session.MergeAsync(parent));
149+
await (session.FlushAsync());
150+
151+
Assert.That(parent.Children, Has.Count.EqualTo(1));
152+
// Merge should duplicate child and leave original instance un-associated with the session.
153+
Assert.That(parent.Children, Does.Not.Contain(child));
154+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
155+
}
156+
}
157+
}
158+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using System;
1+
using System.Collections.Generic;
22

33
namespace NHibernate.Test.NHSpecificTest.GH1754
44
{
55
class Entity
66
{
77
public virtual int Id { get; set; }
88
public virtual string Name { get; set; }
9+
public virtual ISet<Entity> Children { get; set; } = new HashSet<Entity>();
910
}
1011
}

src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Linq;
2-
using NHibernate.Cfg;
32
using NUnit.Framework;
43

54
namespace NHibernate.Test.NHSpecificTest.GH1754
@@ -54,5 +53,94 @@ public void PersistIdentityDoNotSaveIfSessionIsNotFlushed()
5453
Assert.That(count, Is.EqualTo(0));
5554
}
5655
}
56+
57+
// https://hibernate.atlassian.net/browse/HHH-12826
58+
[Test]
59+
public void CanAddChildAfterFlush()
60+
{
61+
using (var session = OpenSession())
62+
{
63+
var parent = new Entity { Name = "Parent" };
64+
var child = new Entity { Name = "Child" };
65+
using (var t = session.BeginTransaction())
66+
{
67+
session.Persist(parent);
68+
session.Flush();
69+
parent.Children.Add(child);
70+
t.Commit();
71+
}
72+
73+
Assert.That(parent.Children, Has.Count.EqualTo(1));
74+
Assert.That(parent.Children, Does.Contain(child));
75+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
76+
}
77+
}
78+
79+
[Test]
80+
public void CanAddChildAfterFlushWithoutTransaction()
81+
{
82+
using (var session = OpenSession())
83+
{
84+
var parent = new Entity { Name = "Parent" };
85+
var child = new Entity { Name = "Child" };
86+
session.Persist(parent);
87+
session.Flush();
88+
parent.Children.Add(child);
89+
session.Flush();
90+
91+
Assert.That(parent.Children, Has.Count.EqualTo(1));
92+
Assert.That(parent.Children, Does.Contain(child));
93+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
94+
}
95+
}
96+
97+
// https://hibernate.atlassian.net/browse/HHH-12846
98+
[Test]
99+
public void CanMergeWithTransientChild()
100+
{
101+
using (var session = OpenSession())
102+
{
103+
var parent = new Entity { Name = "Parent" };
104+
using (var t = session.BeginTransaction())
105+
{
106+
session.Persist(parent);
107+
t.Commit();
108+
}
109+
110+
var child = new Entity { Name = "Child" };
111+
using (var t = session.BeginTransaction())
112+
{
113+
parent.Children.Add(child);
114+
session.Merge(parent);
115+
t.Commit();
116+
}
117+
118+
Assert.That(parent.Children, Has.Count.EqualTo(1));
119+
// Merge should duplicate child and leave original instance un-associated with the session.
120+
Assert.That(parent.Children, Does.Not.Contain(child));
121+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
122+
}
123+
}
124+
125+
[Test]
126+
public void CanMergeWithTransientChildWithoutTransaction()
127+
{
128+
using (var session = OpenSession())
129+
{
130+
var parent = new Entity { Name = "Parent" };
131+
session.Persist(parent);
132+
session.Flush();
133+
134+
var child = new Entity { Name = "Child" };
135+
parent.Children.Add(child);
136+
session.Merge(parent);
137+
session.Flush();
138+
139+
Assert.That(parent.Children, Has.Count.EqualTo(1));
140+
// Merge should duplicate child and leave original instance un-associated with the session.
141+
Assert.That(parent.Children, Does.Not.Contain(child));
142+
Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0));
143+
}
144+
}
57145
}
58146
}

src/NHibernate.Test/NHSpecificTest/GH1754/Mappings.hbm.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
<class name="Entity">
66
<id name="Id" generator="identity"/>
77
<property name="Name"/>
8+
<set name="Children" cascade="persist,merge,save-update,delete-orphan">
9+
<key column="Parent" />
10+
<one-to-many class="Entity"/>
11+
</set>
812
</class>
913

1014
</hibernate-mapping>

src/NHibernate/Async/Engine/Collections.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//------------------------------------------------------------------------------
99

1010

11-
11+
using NHibernate.Action;
1212
using NHibernate.Collection;
1313
using NHibernate.Impl;
1414
using NHibernate.Persister.Collection;
@@ -204,6 +204,7 @@ private static Task PrepareCollectionForUpdateAsync(IPersistentCollection collec
204204
{
205205
// it is or was referenced _somewhere_
206206
bool ownerChanged = loadedPersister != currentPersister ||
207+
!(entry.LoadedKey is DelayedPostInsertIdentifier) &&
207208
!currentPersister.KeyType.IsEqual(entry.LoadedKey, entry.CurrentKey, factory);
208209

209210
if (ownerChanged)

src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Collections.Generic;
1313
using System.Diagnostics;
1414
using System.Text;
15+
using NHibernate.Action;
1516
using NHibernate.Cache;
1617
using NHibernate.Cache.Access;
1718
using NHibernate.Cache.Entry;
@@ -64,7 +65,8 @@ public virtual async Task OnLoadAsync(LoadEvent @event, LoadType loadType, Cance
6465
else
6566
{
6667
System.Type idClass = persister.IdentifierType.ReturnedClass;
67-
if (idClass != null && !idClass.IsInstanceOfType(@event.EntityId))
68+
if (idClass != null && !idClass.IsInstanceOfType(@event.EntityId) &&
69+
!(@event.EntityId is DelayedPostInsertIdentifier))
6870
{
6971
throw new TypeMismatchException("Provided id of the wrong type. Expected: " + idClass + ", got " + @event.EntityId.GetType());
7072
}

src/NHibernate/Engine/Collections.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
using NHibernate.Action;
22
using NHibernate.Collection;
33
using NHibernate.Impl;
44
using NHibernate.Persister.Collection;
@@ -151,6 +151,7 @@ private static void PrepareCollectionForUpdate(IPersistentCollection collection,
151151
{
152152
// it is or was referenced _somewhere_
153153
bool ownerChanged = loadedPersister != currentPersister ||
154+
!(entry.LoadedKey is DelayedPostInsertIdentifier) &&
154155
!currentPersister.KeyType.IsEqual(entry.LoadedKey, entry.CurrentKey, factory);
155156

156157
if (ownerChanged)

src/NHibernate/Event/Default/DefaultLoadEventListener.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.Text;
5+
using NHibernate.Action;
56
using NHibernate.Cache;
67
using NHibernate.Cache.Access;
78
using NHibernate.Cache.Entry;
@@ -60,7 +61,8 @@ public virtual void OnLoad(LoadEvent @event, LoadType loadType)
6061
else
6162
{
6263
System.Type idClass = persister.IdentifierType.ReturnedClass;
63-
if (idClass != null && !idClass.IsInstanceOfType(@event.EntityId))
64+
if (idClass != null && !idClass.IsInstanceOfType(@event.EntityId) &&
65+
!(@event.EntityId is DelayedPostInsertIdentifier))
6466
{
6567
throw new TypeMismatchException("Provided id of the wrong type. Expected: " + idClass + ", got " + @event.EntityId.GetType());
6668
}

0 commit comments

Comments
 (0)