Skip to content

Commit 8124cb5

Browse files
Resolve owner's key correctly in case of property-ref
Reverting initial fix of NH-3480 is re-introducing this related failure, which was lacking adequate tests
1 parent 1102acf commit 8124cb5

File tree

10 files changed

+401
-27
lines changed

10 files changed

+401
-27
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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.Linq;
13+
using NUnit.Framework;
14+
15+
namespace NHibernate.Test.PropertyRef
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class KeyEntityPropertyRefFixtureAsync : TestCase
20+
{
21+
protected override string[] Mappings => new string[] { "PropertyRef.KeyEntityPropertyRef.hbm.xml" };
22+
23+
protected override string MappingsAssembly => "NHibernate.Test";
24+
25+
private int _aWithItemsId;
26+
27+
protected override void OnSetUp()
28+
{
29+
using (var s = OpenSession())
30+
using (var t = s.BeginTransaction())
31+
{
32+
var c1 = new C { Name = "Third" };
33+
s.Save(c1);
34+
var c2 = new C { Name = "ThirdBis" };
35+
s.Save(c2);
36+
37+
var b1 = new B { Id = 1, Name = "SecondC1" };
38+
var b2 = new B { Id = 2, Name = "SecondC2" };
39+
s.Save(b1);
40+
s.Save(b2);
41+
var a = new A { Id = 3, Name = "First", C = c1 };
42+
a.CItems.Add(b1);
43+
a.CItems.Add(b2);
44+
_aWithItemsId = (int) s.Save(a);
45+
46+
s.Save(new A { Id = 4, Name = "FirstBis", C = c2 });
47+
48+
t.Commit();
49+
}
50+
}
51+
52+
protected override void OnTearDown()
53+
{
54+
using (var s = OpenSession())
55+
using (var t = s.BeginTransaction())
56+
{
57+
s.CreateQuery("delete from B").ExecuteUpdate();
58+
s.CreateQuery("delete from A").ExecuteUpdate();
59+
s.CreateQuery("delete from C").ExecuteUpdate();
60+
t.Commit();
61+
}
62+
}
63+
64+
[Test]
65+
public async Task PropertyRefLazyLoadAsync()
66+
{
67+
using (var s = OpenSession())
68+
using (var t = s.BeginTransaction())
69+
{
70+
var a = await (s.GetAsync<A>(_aWithItemsId));
71+
72+
Assert.That(NHibernateUtil.IsInitialized(a.CItems), Is.False, "a with items");
73+
Assert.That(a.CItems, Has.Count.EqualTo(2), "a with items");
74+
await (t.CommitAsync());
75+
}
76+
77+
using (var s = OpenSession())
78+
using (var t = s.BeginTransaction())
79+
{
80+
var entity =
81+
await (s
82+
.Query<A>()
83+
.SingleAsync(a => a.Id != _aWithItemsId));
84+
85+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.False, "a without items");
86+
Assert.That(entity.CItems, Has.Count.EqualTo(0), "a without items");
87+
await (t.CommitAsync());
88+
}
89+
}
90+
91+
[Test]
92+
public async Task PropertyRefEagerLoadAsync()
93+
{
94+
using (var s = OpenSession())
95+
using (var t = s.BeginTransaction())
96+
{
97+
var entity =
98+
await (s
99+
.Query<A>()
100+
.Where(a => a.Id == _aWithItemsId)
101+
.FetchMany(a => a.CItems)
102+
.SingleAsync());
103+
104+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.True, "a with items");
105+
Assert.That(entity.CItems, Has.Count.EqualTo(2), "a with items");
106+
await (t.CommitAsync());
107+
}
108+
109+
using (var s = OpenSession())
110+
using (var t = s.BeginTransaction())
111+
{
112+
var entity =
113+
await (s
114+
.Query<A>()
115+
.Where(a => a.Id != _aWithItemsId)
116+
.FetchMany(a => a.CItems)
117+
.SingleAsync());
118+
119+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.True, "a without items");
120+
Assert.That(entity.CItems, Has.Count.EqualTo(0), "a without items");
121+
await (t.CommitAsync());
122+
}
123+
}
124+
}
125+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
</key>
2828
<one-to-many class="Account"/>
2929
</set>
30+
<!-- Having it mapped after the collection referencing it can cause trouble when resolving the collection, if
31+
not accounted for. So keep it mapped after for checking this case is still supported. -->
3032
<properties name="UserIdAndDeleted" update="false" unique="true">
3133
<property name="UserId" length="8"/>
3234
<property name="Deleted"/>
@@ -55,4 +57,4 @@
5557
<property name="Type" column="`type`" not-null="true"/>
5658
</class>
5759

58-
</hibernate-mapping>
60+
</hibernate-mapping>

src/NHibernate.Test/PropertyRef/A.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ public string Name
2828
set { _name = value; }
2929
}
3030

31-
public virtual ISet<B> Items
31+
public ISet<B> Items
3232
{
3333
get { return _items; }
3434
set { _items = value; }
3535
}
36+
37+
public ISet<B> CItems { get; set; } = new HashSet<B>();
38+
39+
public C C { get; set; }
3640
}
37-
}
41+
}

src/NHibernate.Test/PropertyRef/C.cs

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.PropertyRef
4+
{
5+
public class C
6+
{
7+
public virtual Guid Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
}
11+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.PropertyRef">
4+
<class name="A" lazy="false">
5+
<id name="Id" generator="assigned"/>
6+
<property name="Name"/>
7+
<set name="CItems">
8+
<key column="cid" property-ref="C"/>
9+
<one-to-many class="B"/>
10+
</set>
11+
<!-- Having it mapped after the collection referencing it was causing trouble when resolving the collection -->
12+
<many-to-one name="C"/>
13+
</class>
14+
15+
<class name="B">
16+
<id name="Id" generator="assigned"/>
17+
<property name="Name"/>
18+
</class>
19+
20+
<class name="C">
21+
<id name="Id" generator="guid.comb"/>
22+
<property name="Name"/>
23+
</class>
24+
</hibernate-mapping>
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System.Linq;
2+
using NHibernate.Linq;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.PropertyRef
6+
{
7+
[TestFixture]
8+
public class KeyEntityPropertyRefFixture : TestCase
9+
{
10+
protected override string[] Mappings => new string[] { "PropertyRef.KeyEntityPropertyRef.hbm.xml" };
11+
12+
protected override string MappingsAssembly => "NHibernate.Test";
13+
14+
private int _aWithItemsId;
15+
16+
protected override void OnSetUp()
17+
{
18+
using (var s = OpenSession())
19+
using (var t = s.BeginTransaction())
20+
{
21+
var c1 = new C { Name = "Third" };
22+
s.Save(c1);
23+
var c2 = new C { Name = "ThirdBis" };
24+
s.Save(c2);
25+
26+
var b1 = new B { Id = 1, Name = "SecondC1" };
27+
var b2 = new B { Id = 2, Name = "SecondC2" };
28+
s.Save(b1);
29+
s.Save(b2);
30+
var a = new A { Id = 3, Name = "First", C = c1 };
31+
a.CItems.Add(b1);
32+
a.CItems.Add(b2);
33+
_aWithItemsId = (int) s.Save(a);
34+
35+
s.Save(new A { Id = 4, Name = "FirstBis", C = c2 });
36+
37+
t.Commit();
38+
}
39+
}
40+
41+
protected override void OnTearDown()
42+
{
43+
using (var s = OpenSession())
44+
using (var t = s.BeginTransaction())
45+
{
46+
s.CreateQuery("delete from B").ExecuteUpdate();
47+
s.CreateQuery("delete from A").ExecuteUpdate();
48+
s.CreateQuery("delete from C").ExecuteUpdate();
49+
t.Commit();
50+
}
51+
}
52+
53+
[Test]
54+
public void PropertyRefLazyLoad()
55+
{
56+
using (var s = OpenSession())
57+
using (var t = s.BeginTransaction())
58+
{
59+
var a = s.Get<A>(_aWithItemsId);
60+
61+
Assert.That(NHibernateUtil.IsInitialized(a.CItems), Is.False, "a with items");
62+
Assert.That(a.CItems, Has.Count.EqualTo(2), "a with items");
63+
t.Commit();
64+
}
65+
66+
using (var s = OpenSession())
67+
using (var t = s.BeginTransaction())
68+
{
69+
var entity =
70+
s
71+
.Query<A>()
72+
.Single(a => a.Id != _aWithItemsId);
73+
74+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.False, "a without items");
75+
Assert.That(entity.CItems, Has.Count.EqualTo(0), "a without items");
76+
t.Commit();
77+
}
78+
}
79+
80+
[Test]
81+
public void PropertyRefEagerLoad()
82+
{
83+
using (var s = OpenSession())
84+
using (var t = s.BeginTransaction())
85+
{
86+
var entity =
87+
s
88+
.Query<A>()
89+
.Where(a => a.Id == _aWithItemsId)
90+
.FetchMany(a => a.CItems)
91+
.Single();
92+
93+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.True, "a with items");
94+
Assert.That(entity.CItems, Has.Count.EqualTo(2), "a with items");
95+
t.Commit();
96+
}
97+
98+
using (var s = OpenSession())
99+
using (var t = s.BeginTransaction())
100+
{
101+
var entity =
102+
s
103+
.Query<A>()
104+
.Where(a => a.Id != _aWithItemsId)
105+
.FetchMany(a => a.CItems)
106+
.Single();
107+
108+
Assert.That(NHibernateUtil.IsInitialized(entity.CItems), Is.True, "a without items");
109+
Assert.That(entity.CItems, Has.Count.EqualTo(0), "a without items");
110+
t.Commit();
111+
}
112+
}
113+
}
114+
}

src/NHibernate/Async/Engine/TwoPhaseLoad.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using NHibernate.Type;
2121
using NHibernate.Properties;
2222
using System;
23+
using System.Collections.Generic;
2324

2425
namespace NHibernate.Engine
2526
{
@@ -76,15 +77,28 @@ internal static async Task InitializeEntityAsync(object entity, bool readOnly, I
7677
log.Debug("resolving associations for {0}", MessageHelper.InfoString(persister, id, session.Factory));
7778

7879
IType[] types = persister.PropertyTypes;
80+
var collectionToResolveIndexes = new List<int>(hydratedState.Length);
7981
for (int i = 0; i < hydratedState.Length; i++)
8082
{
8183
object value = hydratedState[i];
8284
if (!Equals(LazyPropertyInitializer.UnfetchedProperty, value) && !(Equals(BackrefPropertyAccessor.Unknown, value)))
8385
{
86+
if (types[i].IsCollectionType)
87+
{
88+
// Resolve them last, because they may depend on other properties if they use a property-ref
89+
collectionToResolveIndexes.Add(i);
90+
continue;
91+
}
92+
8493
hydratedState[i] = await (types[i].ResolveIdentifierAsync(value, session, entity, cancellationToken)).ConfigureAwait(false);
8594
}
8695
}
8796

97+
foreach (var i in collectionToResolveIndexes)
98+
{
99+
hydratedState[i] = await (types[i].ResolveIdentifierAsync(hydratedState[i], session, entity, cancellationToken)).ConfigureAwait(false);
100+
}
101+
88102
//Must occur after resolving identifiers!
89103
if (session.IsEventSource)
90104
{

0 commit comments

Comments
 (0)