Skip to content

Commit ca40016

Browse files
committed
Fix optional join optimistic lock handling
1 parent 8b74774 commit ca40016

File tree

5 files changed

+412
-8
lines changed

5 files changed

+412
-8
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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 NHibernate.Cfg.MappingSchema;
13+
using NHibernate.Mapping.ByCode;
14+
using NUnit.Framework;
15+
using NUnit.Framework.Constraints;
16+
using NHibernate.Linq;
17+
18+
namespace NHibernate.Test.NHSpecificTest.GH1235
19+
{
20+
using System.Threading.Tasks;
21+
//NH-2785
22+
[TestFixture(true, "OptimisticLock")]
23+
[TestFixture(false, "Version")]
24+
[TestFixture(null, "NotVersioned")]
25+
public class OptionalJoinFixtureAsync : TestCaseMappingByCode
26+
{
27+
private readonly bool? _optimisticLock;
28+
29+
public OptionalJoinFixtureAsync(bool? optimisticLock, string comment)
30+
{
31+
_optimisticLock = optimisticLock;
32+
}
33+
34+
protected override void OnTearDown()
35+
{
36+
using (var session = OpenSession())
37+
using (var transaction = session.BeginTransaction())
38+
{
39+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
40+
41+
transaction.Commit();
42+
}
43+
}
44+
45+
[Test]
46+
public async Task UpdateNullOptionalJoinToNotNullAsync()
47+
{
48+
object id;
49+
50+
using (var s = OpenSession())
51+
using (var t = s.BeginTransaction())
52+
{
53+
var entity = new MultiTableEntity { Name = "Bob" };
54+
id = await (s.SaveAsync(entity));
55+
await (t.CommitAsync());
56+
}
57+
58+
using (var s = OpenSession())
59+
using (var t = s.BeginTransaction())
60+
{
61+
var e = await (s.GetAsync<MultiTableEntity>(id));
62+
e.OtherName = "Sally";
63+
await (t.CommitAsync());
64+
}
65+
66+
using (var s = OpenSession())
67+
{
68+
var e = await (s.GetAsync<MultiTableEntity>(id));
69+
Assert.That(e.OtherName, Is.EqualTo("Sally"));
70+
}
71+
}
72+
73+
[Test]
74+
public async Task UpdateNullOptionalJoinToNotNullDetachedAsync()
75+
{
76+
object id;
77+
MultiTableEntity entity;
78+
79+
using (var s = OpenSession())
80+
using (var t = s.BeginTransaction())
81+
{
82+
entity = new MultiTableEntity { Name = "Bob" };
83+
id = await (s.SaveAsync(entity));
84+
await (t.CommitAsync());
85+
}
86+
87+
using (var s = OpenSession())
88+
using (var t = s.BeginTransaction())
89+
{
90+
entity.OtherName = "Sally";
91+
await (s.UpdateAsync(entity));
92+
await (t.CommitAsync());
93+
}
94+
95+
using (var s = OpenSession())
96+
{
97+
var e = await (s.GetAsync<MultiTableEntity>(id));
98+
Assert.That(e.OtherName, Is.EqualTo("Sally"));
99+
}
100+
}
101+
102+
[Test]
103+
public async Task ShouldThrowStaleStateForOptimisticLockUpdateAsync()
104+
{
105+
using (var s = OpenSession())
106+
using (var t = s.BeginTransaction())
107+
108+
{
109+
var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" };
110+
await (s.SaveAsync(result));
111+
await (t.CommitAsync());
112+
}
113+
114+
using (var s1 = OpenSession())
115+
using (var t1 = s1.BeginTransaction())
116+
{
117+
var result = await (s1.Query<MultiTableEntity>().FirstOrDefaultAsync());
118+
119+
result.OtherName += "x";
120+
using (var s2 = OpenSession())
121+
using (var t2 = s2.BeginTransaction())
122+
{
123+
var result2 = await (s2.Query<MultiTableEntity>().FirstOrDefaultAsync());
124+
result2.OtherName += "y";
125+
await (t1.CommitAsync());
126+
Assert.That(
127+
() => t2.CommitAsync(),
128+
_optimisticLock == null
129+
? (IResolveConstraint) Throws.Nothing
130+
: Throws.InstanceOf<StaleObjectStateException>());
131+
}
132+
}
133+
}
134+
135+
[Test]
136+
public async Task ShouldThrowStaleStateForOptimisticLockDeleteAsync()
137+
{
138+
using (var s = OpenSession())
139+
using (var t = s.BeginTransaction())
140+
141+
{
142+
var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" };
143+
await (s.SaveAsync(result));
144+
await (t.CommitAsync());
145+
}
146+
147+
using (var s1 = OpenSession())
148+
using (var t1 = s1.BeginTransaction())
149+
{
150+
var result = await (s1.Query<MultiTableEntity>().FirstOrDefaultAsync());
151+
152+
result.OtherName += "x";
153+
using (var s2 = OpenSession())
154+
using (var t2 = s2.BeginTransaction())
155+
{
156+
var result2 = await (s2.Query<MultiTableEntity>().FirstOrDefaultAsync());
157+
await (s2.DeleteAsync(result2));
158+
await (t1.CommitAsync());
159+
Assert.That(
160+
() => t2.CommitAsync(),
161+
_optimisticLock == null
162+
? (IResolveConstraint) Throws.Nothing
163+
: Throws.InstanceOf<StaleObjectStateException>());
164+
}
165+
}
166+
}
167+
168+
protected override HbmMapping GetMappings()
169+
{
170+
var mapper = new ModelMapper();
171+
mapper.Class<MultiTableEntity>(
172+
rc =>
173+
{
174+
rc.Id(x => x.Id, m => m.Generator(Generators.Native));
175+
rc.DynamicUpdate(true);
176+
177+
if (_optimisticLock == true)
178+
rc.OptimisticLock(OptimisticLockMode.Dirty);
179+
else if (_optimisticLock != null)
180+
rc.Version(x => x.Version, _ => { });
181+
182+
rc.Property(x => x.Name);
183+
rc.Join(
184+
"SecondTable",
185+
m =>
186+
{
187+
m.Key(k => k.Column("Id"));
188+
m.Property(x => x.OtherName);
189+
m.Optional(true);
190+
});
191+
});
192+
193+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
194+
}
195+
}
196+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH1235
4+
{
5+
class MultiTableEntity
6+
{
7+
public virtual int Id { get; set; }
8+
public virtual int Version { get; set; }
9+
public virtual string Name { get; set; }
10+
public virtual string OtherName { get; set; }
11+
}
12+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
using System.Linq;
2+
using NHibernate.Cfg.MappingSchema;
3+
using NHibernate.Mapping.ByCode;
4+
using NUnit.Framework;
5+
using NUnit.Framework.Constraints;
6+
7+
namespace NHibernate.Test.NHSpecificTest.GH1235
8+
{
9+
//NH-2785
10+
[TestFixture(true, "OptimisticLock")]
11+
[TestFixture(false, "Version")]
12+
[TestFixture(null, "NotVersioned")]
13+
public class OptionalJoinFixture : TestCaseMappingByCode
14+
{
15+
private readonly bool? _optimisticLock;
16+
17+
public OptionalJoinFixture(bool? optimisticLock, string comment)
18+
{
19+
_optimisticLock = optimisticLock;
20+
}
21+
22+
protected override void OnTearDown()
23+
{
24+
using (var session = OpenSession())
25+
using (var transaction = session.BeginTransaction())
26+
{
27+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
28+
29+
transaction.Commit();
30+
}
31+
}
32+
33+
[Test]
34+
public void UpdateNullOptionalJoinToNotNull()
35+
{
36+
object id;
37+
38+
using (var s = OpenSession())
39+
using (var t = s.BeginTransaction())
40+
{
41+
var entity = new MultiTableEntity { Name = "Bob" };
42+
id = s.Save(entity);
43+
t.Commit();
44+
}
45+
46+
using (var s = OpenSession())
47+
using (var t = s.BeginTransaction())
48+
{
49+
var e = s.Get<MultiTableEntity>(id);
50+
e.OtherName = "Sally";
51+
t.Commit();
52+
}
53+
54+
using (var s = OpenSession())
55+
{
56+
var e = s.Get<MultiTableEntity>(id);
57+
Assert.That(e.OtherName, Is.EqualTo("Sally"));
58+
}
59+
}
60+
61+
[Test]
62+
public void UpdateNullOptionalJoinToNotNullDetached()
63+
{
64+
object id;
65+
MultiTableEntity entity;
66+
67+
using (var s = OpenSession())
68+
using (var t = s.BeginTransaction())
69+
{
70+
entity = new MultiTableEntity { Name = "Bob" };
71+
id = s.Save(entity);
72+
t.Commit();
73+
}
74+
75+
using (var s = OpenSession())
76+
using (var t = s.BeginTransaction())
77+
{
78+
entity.OtherName = "Sally";
79+
s.Update(entity);
80+
t.Commit();
81+
}
82+
83+
using (var s = OpenSession())
84+
{
85+
var e = s.Get<MultiTableEntity>(id);
86+
Assert.That(e.OtherName, Is.EqualTo("Sally"));
87+
}
88+
}
89+
90+
[Test]
91+
public void ShouldThrowStaleStateForOptimisticLockUpdate()
92+
{
93+
using (var s = OpenSession())
94+
using (var t = s.BeginTransaction())
95+
96+
{
97+
var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" };
98+
s.Save(result);
99+
t.Commit();
100+
}
101+
102+
using (var s1 = OpenSession())
103+
using (var t1 = s1.BeginTransaction())
104+
{
105+
var result = s1.Query<MultiTableEntity>().FirstOrDefault();
106+
107+
result.OtherName += "x";
108+
using (var s2 = OpenSession())
109+
using (var t2 = s2.BeginTransaction())
110+
{
111+
var result2 = s2.Query<MultiTableEntity>().FirstOrDefault();
112+
result2.OtherName += "y";
113+
t1.Commit();
114+
Assert.That(
115+
() => t2.Commit(),
116+
_optimisticLock == null
117+
? (IResolveConstraint) Throws.Nothing
118+
: Throws.InstanceOf<StaleObjectStateException>());
119+
}
120+
}
121+
}
122+
123+
[Test]
124+
public void ShouldThrowStaleStateForOptimisticLockDelete()
125+
{
126+
using (var s = OpenSession())
127+
using (var t = s.BeginTransaction())
128+
129+
{
130+
var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" };
131+
s.Save(result);
132+
t.Commit();
133+
}
134+
135+
using (var s1 = OpenSession())
136+
using (var t1 = s1.BeginTransaction())
137+
{
138+
var result = s1.Query<MultiTableEntity>().FirstOrDefault();
139+
140+
result.OtherName += "x";
141+
using (var s2 = OpenSession())
142+
using (var t2 = s2.BeginTransaction())
143+
{
144+
var result2 = s2.Query<MultiTableEntity>().FirstOrDefault();
145+
s2.Delete(result2);
146+
t1.Commit();
147+
Assert.That(
148+
() => t2.Commit(),
149+
_optimisticLock == null
150+
? (IResolveConstraint) Throws.Nothing
151+
: Throws.InstanceOf<StaleObjectStateException>());
152+
}
153+
}
154+
}
155+
156+
protected override HbmMapping GetMappings()
157+
{
158+
var mapper = new ModelMapper();
159+
mapper.Class<MultiTableEntity>(
160+
rc =>
161+
{
162+
rc.Id(x => x.Id, m => m.Generator(Generators.Native));
163+
rc.DynamicUpdate(true);
164+
165+
if (_optimisticLock == true)
166+
rc.OptimisticLock(OptimisticLockMode.Dirty);
167+
else if (_optimisticLock != null)
168+
rc.Version(x => x.Version, _ => { });
169+
170+
rc.Property(x => x.Name);
171+
rc.Join(
172+
"SecondTable",
173+
m =>
174+
{
175+
m.Key(k => k.Column("Id"));
176+
m.Property(x => x.OtherName);
177+
m.Optional(true);
178+
});
179+
});
180+
181+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)