Skip to content

Commit 7a59132

Browse files
bahusoidfredericDelaporte
authored andcommitted
Fix transient detection for proxy (#2045)
Fixes #2043 in v5.0.x
1 parent 4b51721 commit 7a59132

File tree

11 files changed

+716
-4
lines changed

11 files changed

+716
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
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;
12+
using System.Linq;
13+
using NHibernate.Cfg.MappingSchema;
14+
using NHibernate.Engine;
15+
using NHibernate.Mapping.ByCode;
16+
using NHibernate.Proxy;
17+
using NUnit.Framework;
18+
using NHibernate.Linq;
19+
20+
namespace NHibernate.Test.NHSpecificTest.GH2043
21+
{
22+
using System.Threading.Tasks;
23+
using System.Threading;
24+
[TestFixture]
25+
public class FixtureAsync : TestCaseMappingByCode
26+
{
27+
private Guid _entityWithClassProxy2Id;
28+
private Guid _entityWithInterfaceProxy2Id;
29+
private Guid _entityWithClassLookupId;
30+
private Guid _entityWithInterfaceLookupId;
31+
32+
protected override HbmMapping GetMappings()
33+
{
34+
var mapper = new ModelMapper();
35+
mapper.Class<EntityWithClassProxyDefinition>(rc =>
36+
{
37+
rc.Table("ProxyDefinition");
38+
rc.Proxy(typeof(EntityWithClassProxyDefinition));
39+
40+
rc.Id(x => x.Id);
41+
rc.Property(x => x.Name);
42+
});
43+
44+
mapper.Class<EntityWithInterfaceProxyDefinition>(rc =>
45+
{
46+
rc.Table("IProxyDefinition");
47+
rc.Proxy(typeof(IEntityProxy));
48+
49+
rc.Id(x => x.Id);
50+
rc.Property(x => x.Name);
51+
});
52+
53+
mapper.Class<EntityWithClassLookup>(rc =>
54+
{
55+
rc.Id(x => x.Id);
56+
rc.Property(x => x.Name);
57+
rc.ManyToOne(x => x.EntityLookup, x => x.Class(typeof(EntityWithClassProxyDefinition)));
58+
});
59+
60+
mapper.Class<EntityWithInterfaceLookup>(rc =>
61+
{
62+
rc.Id(x => x.Id);
63+
rc.Property(x => x.Name);
64+
rc.ManyToOne(x => x.EntityLookup, x => x.Class(typeof(EntityWithInterfaceProxyDefinition)));
65+
});
66+
67+
mapper.Class<EntityAssigned>(rc =>
68+
{
69+
rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
70+
rc.Property(x => x.Name);
71+
rc.ManyToOne(x => x.Parent);
72+
});
73+
74+
mapper.Class<EntityWithAssignedBag>(
75+
rc =>
76+
{
77+
rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
78+
rc.Property(x => x.Name);
79+
rc.Bag(
80+
x => x.Children,
81+
m =>
82+
{
83+
m.Inverse(true);
84+
m.Cascade(Mapping.ByCode.Cascade.All | Mapping.ByCode.Cascade.DeleteOrphans);
85+
},
86+
cm => { cm.OneToMany(); });
87+
});
88+
89+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
90+
}
91+
92+
protected override void OnSetUp()
93+
{
94+
using(var session = OpenSession())
95+
using (var transaction = session.BeginTransaction())
96+
{
97+
var entityCP1 = new EntityWithClassProxyDefinition
98+
{
99+
Id = Guid.NewGuid(),
100+
Name = "Name 1"
101+
};
102+
103+
var entityCP2 = new EntityWithClassProxyDefinition
104+
{
105+
Id = Guid.NewGuid(),
106+
Name = "Name 2"
107+
};
108+
_entityWithClassProxy2Id = entityCP2.Id;
109+
110+
var entityIP1 = new EntityWithInterfaceProxyDefinition
111+
{
112+
Id = Guid.NewGuid(),
113+
Name = "Name 1"
114+
};
115+
116+
var entityIP2 = new EntityWithInterfaceProxyDefinition
117+
{
118+
Id = Guid.NewGuid(),
119+
Name = "Name 2"
120+
};
121+
_entityWithInterfaceProxy2Id = entityIP2.Id;
122+
123+
session.Save(entityCP1);
124+
session.Save(entityCP2);
125+
session.Save(entityIP1);
126+
session.Save(entityIP2);
127+
128+
var entityCL = new EntityWithClassLookup
129+
{
130+
Id = Guid.NewGuid(),
131+
Name = "Name 1",
132+
EntityLookup = (EntityWithClassProxyDefinition)session.Load(typeof(EntityWithClassProxyDefinition), entityCP1.Id)
133+
};
134+
_entityWithClassLookupId = entityCL.Id;
135+
136+
var entityIL = new EntityWithInterfaceLookup
137+
{
138+
Id = Guid.NewGuid(),
139+
Name = "Name 1",
140+
EntityLookup = (IEntityProxy)session.Load(typeof(EntityWithInterfaceProxyDefinition), entityIP1.Id)
141+
};
142+
_entityWithInterfaceLookupId = entityIL.Id;
143+
144+
session.Save(entityCL);
145+
session.Save(entityIL);
146+
147+
session.Flush();
148+
transaction.Commit();
149+
}
150+
}
151+
152+
protected override void OnTearDown()
153+
{
154+
using (var session = OpenSession())
155+
using (var transaction = session.BeginTransaction())
156+
{
157+
session.Delete("from System.Object");
158+
159+
session.Flush();
160+
transaction.Commit();
161+
}
162+
}
163+
164+
[Test]
165+
public async Task UpdateEntityWithClassLookupAsync()
166+
{
167+
using (var session = OpenSession())
168+
using (var transaction = session.BeginTransaction())
169+
{
170+
var entityToUpdate = await (session.Query<EntityWithClassLookup>()
171+
.FirstAsync(e => e.Id == _entityWithClassLookupId));
172+
173+
entityToUpdate.EntityLookup = (EntityWithClassProxyDefinition) await (session.LoadAsync(typeof(EntityWithClassProxyDefinition), _entityWithClassProxy2Id));
174+
175+
await (session.UpdateAsync(entityToUpdate));
176+
await (session.FlushAsync());
177+
await (transaction.CommitAsync());
178+
}
179+
}
180+
181+
[Test]
182+
public async Task UpdateEntityWithInterfaceLookupAsync()
183+
{
184+
using (var session = OpenSession())
185+
using (var transaction = session.BeginTransaction())
186+
{
187+
var entityToUpdate = await (session.Query<EntityWithInterfaceLookup>()
188+
.FirstAsync(e => e.Id == _entityWithInterfaceLookupId));
189+
190+
entityToUpdate.EntityLookup = (IEntityProxy) await (session.LoadAsync(typeof(EntityWithInterfaceProxyDefinition), _entityWithInterfaceProxy2Id));
191+
192+
await (session.UpdateAsync(entityToUpdate));
193+
await (session.FlushAsync());
194+
await (transaction.CommitAsync());
195+
}
196+
}
197+
198+
[Test]
199+
public async Task TransientProxySaveAsync()
200+
{
201+
var id = 10;
202+
203+
using (var session = OpenSession())
204+
using(var t = session.BeginTransaction())
205+
{
206+
var e = new EntityAssigned() {Id = id, Name = "a"};
207+
208+
await (session.SaveAsync(e));
209+
await (session.FlushAsync());
210+
await (t.CommitAsync());
211+
}
212+
213+
using (var session = OpenSession())
214+
using(var t = session.BeginTransaction())
215+
{
216+
var e = await (GetTransientProxyAsync(session, id));
217+
await (session.SaveAsync(e));
218+
await (session.FlushAsync());
219+
220+
await (t.CommitAsync());
221+
}
222+
223+
using (var session = OpenSession())
224+
{
225+
var entity = await (session.GetAsync<EntityAssigned>(id));
226+
Assert.That(entity, Is.Not.Null, "Transient proxy wasn't saved");
227+
}
228+
}
229+
230+
[Test]
231+
public async Task TransientProxyBagCascadeSaveAsync()
232+
{
233+
var id = 10;
234+
235+
using (var session = OpenSession())
236+
using(var t = session.BeginTransaction())
237+
{
238+
var e = new EntityAssigned() {Id = id, Name = "a"};
239+
await (session.SaveAsync(e));
240+
await (session.FlushAsync());
241+
await (t.CommitAsync());
242+
}
243+
244+
using (var session = OpenSession())
245+
using(var t = session.BeginTransaction())
246+
{
247+
var child = await (GetTransientProxyAsync(session, id));
248+
var parent = new EntityWithAssignedBag()
249+
{
250+
Id = 1, Name = "p", Children =
251+
{
252+
child
253+
}
254+
};
255+
child.Parent = parent;
256+
257+
await (session.SaveAsync(parent));
258+
await (session.FlushAsync());
259+
260+
await (t.CommitAsync());
261+
}
262+
263+
using (var session = OpenSession())
264+
{
265+
var entity = await (session.GetAsync<EntityAssigned>(id));
266+
Assert.That(entity, Is.Not.Null, "Transient proxy wasn't saved");
267+
}
268+
}
269+
270+
[Test]
271+
public async Task TransientProxyDetectionFromUserCodeAsync()
272+
{
273+
var id = 10;
274+
275+
using (var session = OpenSession())
276+
using (var t = session.BeginTransaction())
277+
{
278+
var e = new EntityAssigned() {Id = id, Name = "a"};
279+
await (session.SaveAsync(e));
280+
await (session.FlushAsync());
281+
await (t.CommitAsync());
282+
}
283+
284+
using (var session = OpenSession())
285+
using (var t = session.BeginTransaction())
286+
{
287+
var child = await (GetTransientProxyAsync(session, id));
288+
Assert.That(await (ForeignKeys.IsTransientSlowAsync(typeof(EntityAssigned).FullName, child, session.GetSessionImplementation(), CancellationToken.None)), Is.True);
289+
await (t.CommitAsync());
290+
}
291+
}
292+
293+
private static async Task<EntityAssigned> GetTransientProxyAsync(ISession session, int id, CancellationToken cancellationToken = default(CancellationToken))
294+
{
295+
EntityAssigned e;
296+
e = await (session.LoadAsync<EntityAssigned>(id, cancellationToken));
297+
e.Name = "b";
298+
await (session.DeleteAsync(e, cancellationToken));
299+
await (session.FlushAsync(cancellationToken));
300+
Assert.That(e.IsProxy(), Is.True, "Failed test set up");
301+
return e;
302+
}
303+
}
304+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace NHibernate.Test.NHSpecificTest.GH2043
2+
{
3+
public class EntityAssigned
4+
{
5+
public virtual int Id { get; set; }
6+
public virtual string Name { get; set; }
7+
public virtual EntityWithAssignedBag Parent { get; set; }
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2043
4+
{
5+
public class EntityWithAssignedBag
6+
{
7+
public virtual int Id { get; set; }
8+
public virtual string Name { get; set; }
9+
public virtual IList<EntityAssigned> Children { get; set; } = new List<EntityAssigned>();
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2043
4+
{
5+
public class EntityWithClassLookup
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
11+
public virtual EntityWithClassProxyDefinition EntityLookup { get; set; }
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2043
4+
{
5+
public class EntityWithClassProxyDefinition
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2043
4+
{
5+
public class EntityWithInterfaceLookup
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
11+
public virtual IEntityProxy EntityLookup { get; set; }
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2043
4+
{
5+
public class EntityWithInterfaceProxyDefinition: IEntityProxy
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
}
11+
}

0 commit comments

Comments
 (0)