Skip to content

Commit 6c252ee

Browse files
authored
Add cross join support for Hql and Linq query provider (#2327)
Fixes: #1128, closes #1060
1 parent 873feec commit 6c252ee

29 files changed

+813
-95
lines changed

src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99

1010

1111
using System;
12+
using System.Collections.Generic;
1213
using System.Linq;
1314
using NHibernate.Cache;
1415
using NHibernate.Cfg;
1516
using NHibernate.Hql.Ast.ANTLR;
1617
using NHibernate.Linq;
1718
using NUnit.Framework;
19+
using NUnit.Framework.Constraints;
1820
using Environment = NHibernate.Cfg.Environment;
1921

2022
namespace NHibernate.Test.FetchLazyProperties
@@ -943,6 +945,42 @@ public async Task TestFetchAfterEntityIsInitializedAsync(bool readOnly)
943945
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Formula"), Is.True);
944946
}
945947

948+
[Test]
949+
public async Task TestHqlCrossJoinFetchFormulaAsync()
950+
{
951+
if (!Dialect.SupportsCrossJoin)
952+
{
953+
Assert.Ignore("Dialect does not support cross join.");
954+
}
955+
956+
var persons = new List<Person>();
957+
var bestFriends = new List<Person>();
958+
using (var sqlSpy = new SqlLogSpy())
959+
using (var s = OpenSession())
960+
{
961+
var list = await (s.CreateQuery("select p, bf from Person p cross join Person bf fetch bf.Formula where bf.Id = p.BestFriend.Id").ListAsync<object[]>());
962+
foreach (var arr in list)
963+
{
964+
persons.Add((Person) arr[0]);
965+
bestFriends.Add((Person) arr[1]);
966+
}
967+
}
968+
969+
AssertPersons(persons, false);
970+
AssertPersons(bestFriends, true);
971+
972+
void AssertPersons(List<Person> results, bool fetched)
973+
{
974+
foreach (var person in results)
975+
{
976+
Assert.That(person, Is.Not.Null);
977+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Image"), Is.False);
978+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Address"), Is.False);
979+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Formula"), fetched ? Is.True : (IResolveConstraint) Is.False);
980+
}
981+
}
982+
}
983+
946984
private static Person GeneratePerson(int i, Person bestFriend)
947985
{
948986
return new Person

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,27 @@ public async Task EntityJoinWithFetchesAsync()
274274
}
275275
}
276276

277+
[Test]
278+
public async Task CrossJoinAndWhereClauseAsync()
279+
{
280+
using (var sqlLog = new SqlLogSpy())
281+
using (var session = OpenSession())
282+
{
283+
var result = await (session.CreateQuery(
284+
"SELECT s " +
285+
"FROM EntityComplex s cross join EntityComplex q " +
286+
"where s.SameTypeChild.Id = q.SameTypeChild.Id"
287+
).ListAsync());
288+
289+
Assert.That(result, Has.Count.EqualTo(1));
290+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
291+
if (Dialect.SupportsCrossJoin)
292+
{
293+
Assert.That(sqlLog.GetWholeLog(), Does.Contain("cross join"), "A cross join is expected in the SQL select");
294+
}
295+
}
296+
}
297+
277298
#region Test Setup
278299

279300
protected override HbmMapping GetMappings()

src/NHibernate.Test/Async/Linq/ByMethod/JoinTests.cs

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

1010

11+
using System;
1112
using System.Linq;
13+
using System.Reflection;
14+
using NHibernate.Cfg;
15+
using NHibernate.Engine.Query;
16+
using NHibernate.Util;
17+
using NSubstitute;
1218
using NUnit.Framework;
1319
using NHibernate.Linq;
1420

@@ -31,5 +37,32 @@ public async Task MultipleLinqJoinsWithSameProjectionNamesAsync()
3137
Assert.That(orders.Count, Is.EqualTo(828));
3238
Assert.IsTrue(orders.All(x => x.FirstId == x.SecondId - 1 && x.SecondId == x.ThirdId - 1));
3339
}
40+
41+
[TestCase(false)]
42+
[TestCase(true)]
43+
public async Task CrossJoinWithPredicateInWhereStatementAsync(bool useCrossJoin)
44+
{
45+
if (useCrossJoin && !Dialect.SupportsCrossJoin)
46+
{
47+
Assert.Ignore("Dialect does not support cross join.");
48+
}
49+
50+
using (var substitute = SubstituteDialect())
51+
using (var sqlSpy = new SqlLogSpy())
52+
{
53+
ClearQueryPlanCache();
54+
substitute.Value.SupportsCrossJoin.Returns(useCrossJoin);
55+
56+
var result = await ((from o in db.Orders
57+
from o2 in db.Orders.Where(x => x.Freight > 50)
58+
where (o.OrderId == o2.OrderId + 1) || (o.OrderId == o2.OrderId - 1)
59+
select new { o.OrderId, OrderId2 = o2.OrderId }).ToListAsync());
60+
61+
var sql = sqlSpy.GetWholeLog();
62+
Assert.That(result.Count, Is.EqualTo(720));
63+
Assert.That(sql, Does.Contain(useCrossJoin ? "cross join" : "inner join"));
64+
Assert.That(GetTotalOccurrences(sql, "inner join"), Is.EqualTo(useCrossJoin ? 0 : 1));
65+
}
66+
}
3467
}
3568
}

0 commit comments

Comments
 (0)