Skip to content

Commit 7ae2b5d

Browse files
committed
Avoid unnecessary join for entity comparisons in with clause
1 parent 21846c0 commit 7ae2b5d

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//------------------------------------------------------------------------------
99

1010

11+
using System.Text.RegularExpressions;
1112
using NHibernate.Cfg.MappingSchema;
1213
using NHibernate.Mapping.ByCode;
1314
using NHibernate.Test.Hql.EntityJoinHqlTestEntities;
@@ -152,6 +153,67 @@ public async Task EntityJoinFoSubqueryAsync()
152153
}
153154
}
154155

156+
[Test]
157+
public async Task EntityJoinWithEntityComparisonInWithClausShouldNotAddJoinAsync()
158+
{
159+
using (var sqlLog = new SqlLogSpy())
160+
using (var session = OpenSession())
161+
{
162+
EntityComplex entityComplex =
163+
await (session
164+
.CreateQuery(
165+
"select ex "
166+
+ "from EntityComplex ex "
167+
+ "inner join EntityComplex st with st = ex.SameTypeChild "
168+
).SetMaxResults(1)
169+
.UniqueResultAsync<EntityComplex>());
170+
171+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(2));
172+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
173+
}
174+
}
175+
176+
[Test]
177+
public async Task EntityJoinWithEntityAssociationComparisonShouldAddJoinAsync()
178+
{
179+
using (var sqlLog = new SqlLogSpy())
180+
using (var session = OpenSession())
181+
{
182+
EntityComplex entityComplex =
183+
await (session
184+
.CreateQuery(
185+
"select ex "
186+
+ "from EntityComplex ex "
187+
+ "inner join EntityComplex st with st = ex.SameTypeChild.SameTypeChild "
188+
).SetMaxResults(1)
189+
.UniqueResultAsync<EntityComplex>());
190+
191+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(3));
192+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
193+
}
194+
}
195+
196+
[Test]
197+
public async Task EntityJoinWithEntityAssociationComparison2ShouldAddJoinAsync()
198+
{
199+
using (var sqlLog = new SqlLogSpy())
200+
using (var session = OpenSession())
201+
{
202+
EntityComplex entityComplex =
203+
await (session
204+
.CreateQuery(
205+
"select ex "
206+
+ "from EntityComplex ex "
207+
+ "inner join EntityComplex st with st.Version = ex.SameTypeChild.Version "
208+
).SetMaxResults(1)
209+
.UniqueResultAsync<EntityComplex>());
210+
211+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(3));
212+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
213+
}
214+
}
215+
216+
155217
[Test, Ignore("Failing for unrelated reasons")]
156218
public async Task CrossJoinAndWithClauseAsync()
157219
{

src/NHibernate.Test/Hql/EntityJoinHqlTest.cs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using NHibernate.Cfg.MappingSchema;
1+
using System.Text.RegularExpressions;
2+
using NHibernate.Cfg.MappingSchema;
23
using NHibernate.Mapping.ByCode;
34
using NHibernate.Test.Hql.EntityJoinHqlTestEntities;
45
using NUnit.Framework;
@@ -141,6 +142,67 @@ public void EntityJoinFoSubquery()
141142
}
142143
}
143144

145+
[Test]
146+
public void EntityJoinWithEntityComparisonInWithClausShouldNotAddJoin()
147+
{
148+
using (var sqlLog = new SqlLogSpy())
149+
using (var session = OpenSession())
150+
{
151+
EntityComplex entityComplex =
152+
session
153+
.CreateQuery(
154+
"select ex "
155+
+ "from EntityComplex ex "
156+
+ "inner join EntityComplex st with st = ex.SameTypeChild "
157+
).SetMaxResults(1)
158+
.UniqueResult<EntityComplex>();
159+
160+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(2));
161+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
162+
}
163+
}
164+
165+
[Test]
166+
public void EntityJoinWithEntityAssociationComparisonShouldAddJoin()
167+
{
168+
using (var sqlLog = new SqlLogSpy())
169+
using (var session = OpenSession())
170+
{
171+
EntityComplex entityComplex =
172+
session
173+
.CreateQuery(
174+
"select ex "
175+
+ "from EntityComplex ex "
176+
+ "inner join EntityComplex st with st = ex.SameTypeChild.SameTypeChild "
177+
).SetMaxResults(1)
178+
.UniqueResult<EntityComplex>();
179+
180+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(3));
181+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
182+
}
183+
}
184+
185+
[Test]
186+
public void EntityJoinWithEntityAssociationComparison2ShouldAddJoin()
187+
{
188+
using (var sqlLog = new SqlLogSpy())
189+
using (var session = OpenSession())
190+
{
191+
EntityComplex entityComplex =
192+
session
193+
.CreateQuery(
194+
"select ex "
195+
+ "from EntityComplex ex "
196+
+ "inner join EntityComplex st with st.Version = ex.SameTypeChild.Version "
197+
).SetMaxResults(1)
198+
.UniqueResult<EntityComplex>();
199+
200+
Assert.That(Regex.Matches(sqlLog.GetWholeLog(), "EntityComplex").Count, Is.EqualTo(3));
201+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
202+
}
203+
}
204+
205+
144206
[Test, Ignore("Failing for unrelated reasons")]
145207
public void CrossJoinAndWithClause()
146208
{

src/NHibernate/Hql/Ast/ANTLR/Tree/DotNode.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,9 @@ private void DereferenceEntity(EntityType entityType, bool implicitJoin, string
407407
// this is the regression style determination which matches the logic of the classic translator
408408
joinIsNeeded = generateJoin && ( !Walker.IsInSelect || !Walker.IsShallowQuery);
409409
}
410-
else
410+
else
411411
{
412-
joinIsNeeded = generateJoin || ( (Walker.IsInSelect && !Walker.IsInCase ) || Walker.IsInFrom );
412+
joinIsNeeded = generateJoin || ((Walker.IsInSelect && !Walker.IsInCase) || (Walker.IsInFrom && !Walker.IsComparativeExpressionClause));
413413
}
414414

415415
if ( joinIsNeeded )

0 commit comments

Comments
 (0)