Skip to content

Commit 59b07b8

Browse files
bahusoidhazzik
authored andcommitted
Fix wrong inner join on component key many-to-one property in Criteria
1 parent 74ff7a1 commit 59b07b8

File tree

3 files changed

+414
-3
lines changed

3 files changed

+414
-3
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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.Collections.Generic;
12+
using System.Linq;
13+
using NHibernate.Mapping.ByCode;
14+
using NUnit.Framework;
15+
16+
namespace NHibernate.Test.NHSpecificTest.NH3813
17+
{
18+
using System.Threading.Tasks;
19+
[TestFixture]
20+
public class KeyManyToOneInnerJoinFetchFixtureAsync : TestCaseMappingByCode
21+
{
22+
protected override Cfg.MappingSchema.HbmMapping GetMappings()
23+
{
24+
var mapper = new ModelMapper();
25+
26+
mapper.Class<FirstTable>(
27+
m =>
28+
{
29+
m.Lazy(false);
30+
31+
m.Id(
32+
i => i.ID,
33+
id =>
34+
{
35+
id.Column("ID");
36+
id.Generator(Generators.Identity);
37+
});
38+
39+
m.Bag(
40+
b => b.AssociationTableCollection,
41+
bm =>
42+
{
43+
bm.Inverse(true);
44+
bm.Key(k => k.Column("FirstTableID"));
45+
},
46+
mp => mp.OneToMany());
47+
});
48+
49+
mapper.Class<OtherTable>(
50+
m =>
51+
{
52+
m.Lazy(false);
53+
54+
m.Id(
55+
i => i.ID,
56+
id =>
57+
{
58+
id.Column("ID");
59+
id.Generator(Generators.Identity);
60+
});
61+
});
62+
63+
mapper.Class<AssociationTable>(
64+
m =>
65+
{
66+
m.ComposedId(
67+
i =>
68+
{
69+
i.ManyToOne(c => c.FirstTable, p => { p.Column("FirstTableID"); });
70+
71+
i.ManyToOne(c => c.OtherTable, p => { p.Column("OtherTableID"); });
72+
});
73+
});
74+
75+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
76+
}
77+
78+
[Test]
79+
public async Task FetchQueryDoesNotContainInnerJoinAsync()
80+
{
81+
using (var logSpy = new SqlLogSpy())
82+
using (var session = OpenSession())
83+
{
84+
var q = await (session.QueryOver<FirstTable>()
85+
.Fetch(SelectMode.Fetch, f => f.AssociationTableCollection)
86+
.Left.JoinQueryOver(f => f.AssociationTableCollection).ListAsync());
87+
88+
var sql = logSpy.GetWholeLog();
89+
Assert.That(sql, Is.Not.Contains("inner join"));
90+
}
91+
}
92+
93+
[Test]
94+
public async Task FetchQueryDoesNotContainInnerJoinMultiAsync()
95+
{
96+
using (var logSpy = new SqlLogSpy())
97+
using (var session = OpenSession())
98+
{
99+
var q = await (session.QueryOver<FirstTable>()
100+
.Fetch(SelectMode.Fetch, f => f.AssociationTableCollection)
101+
.Left.JoinQueryOver<AssociationTable>(f => f.AssociationTableCollection)
102+
.Left.JoinQueryOver(a => a.OtherTable).ListAsync());
103+
104+
var sql = logSpy.GetWholeLog();
105+
106+
Assert.That(sql, Does.Not.Contain("inner join"));
107+
Assert.That(sql, Does.Match(@"join\s*AssociationTable").IgnoreCase);
108+
Assert.That(sql, Does.Match(@"join\s*OtherTable"));
109+
}
110+
}
111+
112+
[Test]
113+
public async Task FetchLoadsAllRecordsAsync()
114+
{
115+
IList<FirstTable> result = null;
116+
117+
using (var session = OpenSession())
118+
{
119+
// the query should return all records from the table with their collections fetched
120+
result = await (session.QueryOver<FirstTable>()
121+
.Fetch(SelectMode.Fetch, f => f.AssociationTableCollection)
122+
.Left.JoinQueryOver(f => f.AssociationTableCollection)
123+
.ListAsync());
124+
}
125+
126+
Assert.AreEqual(2, result.Count, "Query returned wrong number of records.");
127+
Assert.IsTrue(result.All(x => NHibernateUtil.IsInitialized(x.AssociationTableCollection)), "Not all collections have been initialized");
128+
}
129+
130+
[Test]
131+
public async Task FetchInitializesAllCollectionsAsync()
132+
{
133+
IList<FirstTable> result = null;
134+
135+
using (var session = OpenSession())
136+
{
137+
// load all records
138+
result = await (session.QueryOver<FirstTable>()
139+
.ListAsync());
140+
141+
// lazy-load the association collection
142+
await (session.QueryOver<FirstTable>()
143+
.Fetch(SelectMode.Fetch, f => f.AssociationTableCollection)
144+
.Left.JoinQueryOver(f => f.AssociationTableCollection)
145+
.ListAsync());
146+
}
147+
148+
Assert.IsTrue(result.All(x => NHibernateUtil.IsInitialized(x.AssociationTableCollection)), "Not all collections have been initialized");
149+
}
150+
151+
protected override void OnSetUp()
152+
{
153+
base.OnSetUp();
154+
155+
using (ISession s = OpenSession())
156+
using (ITransaction t = s.BeginTransaction())
157+
{
158+
// a record that has association records will be loaded regularly
159+
var withAssociations = new FirstTable();
160+
161+
var other1 = new OtherTable();
162+
var other2 = new OtherTable();
163+
164+
var assoc1 = new AssociationTable() {OtherTable = other1, FirstTable = withAssociations};
165+
var assoc2 = new AssociationTable() {OtherTable = other2, FirstTable = withAssociations};
166+
167+
withAssociations.AssociationTableCollection.Add(assoc1);
168+
withAssociations.AssociationTableCollection.Add(assoc2);
169+
s.Save(withAssociations);
170+
171+
// a record with no associations will have problems if inner joined to association table
172+
var withoutAssociations = new FirstTable();
173+
s.Save(withoutAssociations);
174+
175+
t.Commit();
176+
}
177+
}
178+
179+
protected override void OnTearDown()
180+
{
181+
using (ISession s = OpenSession())
182+
using (ITransaction t = s.BeginTransaction())
183+
{
184+
s.Delete("from AssociationTable");
185+
s.Delete("from OtherTable");
186+
s.Delete("from FirstTable");
187+
t.Commit();
188+
}
189+
190+
base.OnTearDown();
191+
}
192+
}
193+
}

0 commit comments

Comments
 (0)