Skip to content

Commit e99cf43

Browse files
Improve exception for query on delayed id (#3043)
Related: #3041
1 parent 1467f5f commit e99cf43

File tree

9 files changed

+372
-68
lines changed

9 files changed

+372
-68
lines changed

src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs

Lines changed: 228 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
//------------------------------------------------------------------------------
99

1010

11+
using System.Linq;
1112
using NHibernate.Cfg;
13+
using NHibernate.Exceptions;
1214
using NUnit.Framework;
1315

1416
namespace NHibernate.Test.Generatedkeys.Identity
@@ -38,17 +40,238 @@ protected override void Configure(Configuration configuration)
3840
configuration.SetProperty(Environment.GenerateStatistics, "true");
3941
}
4042

43+
protected override void OnTearDown()
44+
{
45+
using (var s = OpenSession())
46+
using (var t = s.BeginTransaction())
47+
{
48+
s.CreateQuery("delete from MyChild").ExecuteUpdate();
49+
s.CreateQuery("delete from MySibling").ExecuteUpdate();
50+
s.CreateQuery("delete from System.Object").ExecuteUpdate();
51+
t.Commit();
52+
s.Close();
53+
}
54+
}
55+
4156
[Test]
4257
public async Task IdentityColumnGeneratedIdsAsync()
4358
{
4459
using (var s = OpenSession())
4560
using (var t = s.BeginTransaction())
4661
{
47-
MyEntity myEntity = new MyEntity("test");
48-
long id = (long) await (s.SaveAsync(myEntity));
49-
Assert.IsNotNull(id, "identity column did not force immediate insert");
50-
Assert.AreEqual(id, myEntity.Id);
51-
await (s.DeleteAsync(myEntity));
62+
var entity1 = new MyEntity("test");
63+
var id1 = (long) await (s.SaveAsync(entity1));
64+
var entity2 = new MyEntity("test2");
65+
var id2 = (long) await (s.SaveAsync(entity2));
66+
// As 0 may be a valid identity value, we check for returned ids being not the same when saving two entities.
67+
Assert.That(id1, Is.Not.EqualTo(id2), "identity column did not force immediate insert");
68+
Assert.That(id1, Is.EqualTo(entity1.Id));
69+
Assert.That(id2, Is.EqualTo(entity2.Id));
70+
await (t.CommitAsync());
71+
s.Close();
72+
}
73+
}
74+
75+
[Test]
76+
public async Task PersistOutsideTransactionAsync()
77+
{
78+
var myEntity1 = new MyEntity("test-save");
79+
var myEntity2 = new MyEntity("test-persist");
80+
using (var s = OpenSession())
81+
{
82+
// first test save() which should force an immediate insert...
83+
var initialInsertCount = Sfi.Statistics.EntityInsertCount;
84+
var id = (long) await (s.SaveAsync(myEntity1));
85+
Assert.That(
86+
Sfi.Statistics.EntityInsertCount,
87+
Is.GreaterThan(initialInsertCount),
88+
"identity column did not force immediate insert");
89+
Assert.That(id, Is.EqualTo(myEntity1.Id));
90+
91+
// next test persist() which should cause a delayed insert...
92+
initialInsertCount = Sfi.Statistics.EntityInsertCount;
93+
await (s.PersistAsync(myEntity2));
94+
Assert.AreEqual(
95+
initialInsertCount,
96+
Sfi.Statistics.EntityInsertCount,
97+
"persist on identity column not delayed");
98+
Assert.AreEqual(0, myEntity2.Id);
99+
100+
// an explicit flush should cause execution of the delayed insertion
101+
await (s.FlushAsync());
102+
Assert.AreEqual(
103+
initialInsertCount + 1,
104+
Sfi.Statistics.EntityInsertCount,
105+
"delayed persist insert not executed on flush");
106+
s.Close();
107+
}
108+
109+
using (var s = OpenSession())
110+
using (var t = s.BeginTransaction())
111+
{
112+
await (s.DeleteAsync(myEntity1));
113+
await (s.DeleteAsync(myEntity2));
114+
await (t.CommitAsync());
115+
s.Close();
116+
}
117+
}
118+
119+
[Test]
120+
public async Task PersistOutsideTransactionCascadedToNonInverseCollectionAsync()
121+
{
122+
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
123+
using (var s = OpenSession())
124+
{
125+
MyEntity myEntity = new MyEntity("test-persist");
126+
myEntity.NonInverseChildren.Add(new MyChild("test-child-persist-non-inverse"));
127+
await (s.PersistAsync(myEntity));
128+
Assert.AreEqual(
129+
initialInsertCount,
130+
Sfi.Statistics.EntityInsertCount,
131+
"persist on identity column not delayed");
132+
Assert.AreEqual(0, myEntity.Id);
133+
await (s.FlushAsync());
134+
Assert.AreEqual(
135+
initialInsertCount + 2,
136+
Sfi.Statistics.EntityInsertCount,
137+
"delayed persist insert not executed on flush");
138+
s.Close();
139+
}
140+
141+
using (var s = OpenSession())
142+
using (var t = s.BeginTransaction())
143+
{
144+
await (s.DeleteAsync("from MyChild"));
145+
await (s.DeleteAsync("from MyEntity"));
146+
await (t.CommitAsync());
147+
s.Close();
148+
}
149+
}
150+
151+
[Test]
152+
public async Task PersistOutsideTransactionCascadedToInverseCollectionAsync()
153+
{
154+
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
155+
using (var s = OpenSession())
156+
{
157+
MyEntity myEntity2 = new MyEntity("test-persist-2");
158+
MyChild child = new MyChild("test-child-persist-inverse");
159+
myEntity2.InverseChildren.Add(child);
160+
child.InverseParent = myEntity2;
161+
await (s.PersistAsync(myEntity2));
162+
Assert.AreEqual(
163+
initialInsertCount,
164+
Sfi.Statistics.EntityInsertCount,
165+
"persist on identity column not delayed");
166+
Assert.AreEqual(0, myEntity2.Id);
167+
await (s.FlushAsync());
168+
Assert.AreEqual(
169+
initialInsertCount + 2,
170+
Sfi.Statistics.EntityInsertCount,
171+
"delayed persist insert not executed on flush");
172+
s.Close();
173+
}
174+
175+
using (var s = OpenSession())
176+
using (var t = s.BeginTransaction())
177+
{
178+
await (s.DeleteAsync("from MyChild"));
179+
await (s.DeleteAsync("from MyEntity"));
180+
await (t.CommitAsync());
181+
s.Close();
182+
}
183+
}
184+
185+
[Test]
186+
public async Task PersistOutsideTransactionCascadedToManyToOneAsync()
187+
{
188+
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
189+
using (var s = OpenSession())
190+
{
191+
MyEntity myEntity = new MyEntity("test-persist");
192+
myEntity.Sibling = new MySibling("test-persist-sibling-out");
193+
await (s.PersistAsync(myEntity));
194+
Assert.AreEqual(
195+
initialInsertCount,
196+
Sfi.Statistics.EntityInsertCount,
197+
"persist on identity column not delayed");
198+
Assert.AreEqual(0, myEntity.Id);
199+
await (s.FlushAsync());
200+
Assert.AreEqual(
201+
initialInsertCount + 2,
202+
Sfi.Statistics.EntityInsertCount,
203+
"delayed persist insert not executed on flush");
204+
s.Close();
205+
}
206+
207+
using (var s = OpenSession())
208+
using (var t = s.BeginTransaction())
209+
{
210+
await (s.DeleteAsync("from MyEntity"));
211+
await (s.DeleteAsync("from MySibling"));
212+
await (t.CommitAsync());
213+
s.Close();
214+
}
215+
}
216+
217+
[Test]
218+
public async Task PersistOutsideTransactionCascadedFromManyToOneAsync()
219+
{
220+
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
221+
using (var s = OpenSession())
222+
{
223+
MyEntity myEntity2 = new MyEntity("test-persist-2");
224+
MySibling sibling = new MySibling("test-persist-sibling-in");
225+
sibling.Entity = myEntity2;
226+
await (s.PersistAsync(sibling));
227+
Assert.AreEqual(
228+
initialInsertCount,
229+
Sfi.Statistics.EntityInsertCount,
230+
"persist on identity column not delayed");
231+
Assert.AreEqual(0, myEntity2.Id);
232+
await (s.FlushAsync());
233+
Assert.AreEqual(
234+
initialInsertCount + 2,
235+
Sfi.Statistics.EntityInsertCount,
236+
"delayed persist insert not executed on flush");
237+
s.Close();
238+
}
239+
240+
using (var s = OpenSession())
241+
using (var t = s.BeginTransaction())
242+
{
243+
await (s.DeleteAsync("from MySibling"));
244+
await (s.DeleteAsync("from MyEntity"));
245+
await (t.CommitAsync());
246+
s.Close();
247+
}
248+
}
249+
250+
[Test]
251+
public async Task QueryOnPersistedEntityAsync([Values(FlushMode.Auto, FlushMode.Commit)] FlushMode flushMode)
252+
{
253+
var myEntity = new MyEntity("test-persist");
254+
using (var s = OpenSession())
255+
using (var t = s.BeginTransaction())
256+
{
257+
s.FlushMode = flushMode;
258+
259+
var initialInsertCount = Sfi.Statistics.EntityInsertCount;
260+
await (s.PersistAsync(myEntity));
261+
Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(initialInsertCount),
262+
"persist on identity column not delayed");
263+
Assert.That(myEntity.Id, Is.Zero);
264+
265+
var query = s.Query<MyChild>().Where(c => c.InverseParent == myEntity);
266+
switch (flushMode)
267+
{
268+
case FlushMode.Auto:
269+
Assert.That(query.ToList, Throws.Nothing);
270+
break;
271+
case FlushMode.Commit:
272+
Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(UnresolvableObjectException)));
273+
break;
274+
}
52275
await (t.CommitAsync());
53276
s.Close();
54277
}

src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System.Linq;
12
using NHibernate.Cfg;
3+
using NHibernate.Exceptions;
24
using NUnit.Framework;
35

46
namespace NHibernate.Test.Generatedkeys.Identity
@@ -27,36 +29,56 @@ protected override void Configure(Configuration configuration)
2729
configuration.SetProperty(Environment.GenerateStatistics, "true");
2830
}
2931

32+
protected override void OnTearDown()
33+
{
34+
using (var s = OpenSession())
35+
using (var t = s.BeginTransaction())
36+
{
37+
s.CreateQuery("delete from MyChild").ExecuteUpdate();
38+
s.CreateQuery("delete from MySibling").ExecuteUpdate();
39+
s.CreateQuery("delete from System.Object").ExecuteUpdate();
40+
t.Commit();
41+
s.Close();
42+
}
43+
}
44+
3045
[Test]
3146
public void IdentityColumnGeneratedIds()
3247
{
3348
using (var s = OpenSession())
3449
using (var t = s.BeginTransaction())
3550
{
36-
MyEntity myEntity = new MyEntity("test");
37-
long id = (long) s.Save(myEntity);
38-
Assert.IsNotNull(id, "identity column did not force immediate insert");
39-
Assert.AreEqual(id, myEntity.Id);
40-
s.Delete(myEntity);
51+
var entity1 = new MyEntity("test");
52+
var id1 = (long) s.Save(entity1);
53+
var entity2 = new MyEntity("test2");
54+
var id2 = (long) s.Save(entity2);
55+
// As 0 may be a valid identity value, we check for returned ids being not the same when saving two entities.
56+
Assert.That(id1, Is.Not.EqualTo(id2), "identity column did not force immediate insert");
57+
Assert.That(id1, Is.EqualTo(entity1.Id));
58+
Assert.That(id2, Is.EqualTo(entity2.Id));
4159
t.Commit();
4260
s.Close();
4361
}
4462
}
4563

46-
[Test, Ignore("Not supported yet.")]
64+
[Test]
4765
public void PersistOutsideTransaction()
4866
{
4967
var myEntity1 = new MyEntity("test-save");
5068
var myEntity2 = new MyEntity("test-persist");
5169
using (var s = OpenSession())
5270
{
5371
// first test save() which should force an immediate insert...
54-
long id = (long) s.Save(myEntity1);
55-
Assert.IsNotNull(id, "identity column did not force immediate insert");
56-
Assert.AreEqual(id, myEntity1.Id);
72+
var initialInsertCount = Sfi.Statistics.EntityInsertCount;
73+
var id = (long) s.Save(myEntity1);
74+
Assert.That(
75+
Sfi.Statistics.EntityInsertCount,
76+
Is.GreaterThan(initialInsertCount),
77+
"identity column did not force immediate insert");
78+
Assert.That(id, Is.EqualTo(myEntity1.Id));
5779

5880
// next test persist() which should cause a delayed insert...
59-
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
81+
initialInsertCount = Sfi.Statistics.EntityInsertCount;
6082
s.Persist(myEntity2);
6183
Assert.AreEqual(
6284
initialInsertCount,
@@ -83,7 +105,7 @@ public void PersistOutsideTransaction()
83105
}
84106
}
85107

86-
[Test, Ignore("Not supported yet.")]
108+
[Test]
87109
public void PersistOutsideTransactionCascadedToNonInverseCollection()
88110
{
89111
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
@@ -115,7 +137,7 @@ public void PersistOutsideTransactionCascadedToNonInverseCollection()
115137
}
116138
}
117139

118-
[Test, Ignore("Not supported yet.")]
140+
[Test]
119141
public void PersistOutsideTransactionCascadedToInverseCollection()
120142
{
121143
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
@@ -149,7 +171,7 @@ public void PersistOutsideTransactionCascadedToInverseCollection()
149171
}
150172
}
151173

152-
[Test, Ignore("Not supported yet.")]
174+
[Test]
153175
public void PersistOutsideTransactionCascadedToManyToOne()
154176
{
155177
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
@@ -181,7 +203,7 @@ public void PersistOutsideTransactionCascadedToManyToOne()
181203
}
182204
}
183205

184-
[Test, Ignore("Not supported yet.")]
206+
[Test]
185207
public void PersistOutsideTransactionCascadedFromManyToOne()
186208
{
187209
long initialInsertCount = Sfi.Statistics.EntityInsertCount;
@@ -213,5 +235,35 @@ public void PersistOutsideTransactionCascadedFromManyToOne()
213235
s.Close();
214236
}
215237
}
238+
239+
[Test]
240+
public void QueryOnPersistedEntity([Values(FlushMode.Auto, FlushMode.Commit)] FlushMode flushMode)
241+
{
242+
var myEntity = new MyEntity("test-persist");
243+
using (var s = OpenSession())
244+
using (var t = s.BeginTransaction())
245+
{
246+
s.FlushMode = flushMode;
247+
248+
var initialInsertCount = Sfi.Statistics.EntityInsertCount;
249+
s.Persist(myEntity);
250+
Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(initialInsertCount),
251+
"persist on identity column not delayed");
252+
Assert.That(myEntity.Id, Is.Zero);
253+
254+
var query = s.Query<MyChild>().Where(c => c.InverseParent == myEntity);
255+
switch (flushMode)
256+
{
257+
case FlushMode.Auto:
258+
Assert.That(query.ToList, Throws.Nothing);
259+
break;
260+
case FlushMode.Commit:
261+
Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(UnresolvableObjectException)));
262+
break;
263+
}
264+
t.Commit();
265+
s.Close();
266+
}
267+
}
216268
}
217269
}

0 commit comments

Comments
 (0)