Skip to content

Commit 21ab72e

Browse files
committed
Add cross join support for Hql and Linq query provider
1 parent 873feec commit 21ab72e

20 files changed

+168
-15
lines changed

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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,31 @@ public async Task MultipleLinqJoinsWithSameProjectionNamesAsync()
3131
Assert.That(orders.Count, Is.EqualTo(828));
3232
Assert.IsTrue(orders.All(x => x.FirstId == x.SecondId - 1 && x.SecondId == x.ThirdId - 1));
3333
}
34+
35+
[Test]
36+
public async Task CrossJoinWithPredicateInOnStatementAsync()
37+
{
38+
var result =
39+
await ((from o in db.Orders
40+
from p in db.Products
41+
join d in db.OrderLines
42+
on new { o.OrderId, p.ProductId } equals new { d.Order.OrderId, d.Product.ProductId }
43+
into details
44+
from d in details
45+
select new { o.OrderId, p.ProductId, d.UnitPrice }).Take(10).ToListAsync());
46+
47+
Assert.That(result.Count, Is.EqualTo(10));
48+
}
49+
50+
[Test]
51+
public async Task CrossJoinWithPredicateInWhereStatementAsync()
52+
{
53+
var result = await ((from o in db.Orders
54+
from o2 in db.Orders.Where(x => x.Freight > 50)
55+
where (o.OrderId == o2.OrderId + 1) || (o.OrderId == o2.OrderId - 1)
56+
select new { o.OrderId, OrderId2 = o2.OrderId }).ToListAsync());
57+
58+
Assert.That(result.Count, Is.EqualTo(720));
59+
}
3460
}
3561
}

src/NHibernate.Test/Hql/EntityJoinHqlTest.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public void EntityJoinWithFetches()
264264
}
265265

266266
[Test, Ignore("Failing for unrelated reasons")]
267-
public void CrossJoinAndWithClause()
267+
public void ImplicitJoinAndWithClause()
268268
{
269269
//This is about complex theta style join fix that was implemented in hibernate along with entity join functionality
270270
//https://hibernate.atlassian.net/browse/HHH-7321
@@ -279,6 +279,27 @@ public void CrossJoinAndWithClause()
279279
}
280280
}
281281

282+
[Test]
283+
public void CrossJoinAndWhereClause()
284+
{
285+
using (var sqlLog = new SqlLogSpy())
286+
using (var session = OpenSession())
287+
{
288+
var result = session.CreateQuery(
289+
"SELECT s " +
290+
"FROM EntityComplex s cross join EntityComplex q " +
291+
"where s.SameTypeChild.Id = q.SameTypeChild.Id"
292+
).List();
293+
294+
Assert.That(result, Has.Count.EqualTo(1));
295+
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
296+
if (Dialect.SupportsCrossJoin)
297+
{
298+
Assert.That(sqlLog.GetWholeLog(), Does.Contain("cross join"), "A cross join is expected in the SQL select");
299+
}
300+
}
301+
}
302+
282303
#region Test Setup
283304

284305
protected override HbmMapping GetMappings()

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,31 @@ public void MultipleLinqJoinsWithSameProjectionNames()
1919
Assert.That(orders.Count, Is.EqualTo(828));
2020
Assert.IsTrue(orders.All(x => x.FirstId == x.SecondId - 1 && x.SecondId == x.ThirdId - 1));
2121
}
22+
23+
[Test]
24+
public void CrossJoinWithPredicateInOnStatement()
25+
{
26+
var result =
27+
(from o in db.Orders
28+
from p in db.Products
29+
join d in db.OrderLines
30+
on new { o.OrderId, p.ProductId } equals new { d.Order.OrderId, d.Product.ProductId }
31+
into details
32+
from d in details
33+
select new { o.OrderId, p.ProductId, d.UnitPrice }).Take(10).ToList();
34+
35+
Assert.That(result.Count, Is.EqualTo(10));
36+
}
37+
38+
[Test]
39+
public void CrossJoinWithPredicateInWhereStatement()
40+
{
41+
var result = (from o in db.Orders
42+
from o2 in db.Orders.Where(x => x.Freight > 50)
43+
where (o.OrderId == o2.OrderId + 1) || (o.OrderId == o2.OrderId - 1)
44+
select new { o.OrderId, OrderId2 = o2.OrderId }).ToList();
45+
46+
Assert.That(result.Count, Is.EqualTo(720));
47+
}
2248
}
2349
}

src/NHibernate/AdoNet/Util/BasicFormatter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ static BasicFormatter()
2020
{
2121
beginClauses.Add("left");
2222
beginClauses.Add("right");
23+
beginClauses.Add("cross");
2324
beginClauses.Add("inner");
2425
beginClauses.Add("outer");
2526
beginClauses.Add("group");

src/NHibernate/Dialect/DB2Dialect.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ public override string ForUpdateString
300300

301301
public override bool SupportsResultSetPositionQueryMethodsOnForwardOnlyCursor => false;
302302

303+
/// <inheritdoc />
304+
public override bool SupportsCrossJoin => false; // DB2 v9.1 doesn't support 'cross join' syntax
305+
303306
public override bool SupportsLobValueChangePropogation => false;
304307

305308
public override bool SupportsExistsInSelect => false;

src/NHibernate/Dialect/Dialect.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,11 @@ public virtual JoinFragment CreateOuterJoinFragment()
13371337
return new ANSIJoinFragment();
13381338
}
13391339

1340+
/// <summary>
1341+
/// Does this dialect support CROSS JOIN?
1342+
/// </summary>
1343+
public virtual bool SupportsCrossJoin => true;
1344+
13401345
/// <summary>
13411346
/// Create a <see cref="CaseFragment"/> strategy responsible
13421347
/// for handling this dialect's variations in how CASE statements are

src/NHibernate/Dialect/InformixDialect0940.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ public override JoinFragment CreateOuterJoinFragment()
126126
return new ANSIJoinFragment();
127127
}
128128

129-
/// <summary>
129+
/// <inheritdoc />
130+
public override bool SupportsCrossJoin => false;
131+
132+
/// <summary>
130133
/// Does this Dialect have some kind of <c>LIMIT</c> syntax?
131134
/// </summary>
132135
/// <value>False, unless overridden.</value>

src/NHibernate/Dialect/Oracle10gDialect.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ public override JoinFragment CreateOuterJoinFragment()
1515
{
1616
return new ANSIJoinFragment();
1717
}
18+
19+
/// <inheritdoc />
20+
public override bool SupportsCrossJoin => true;
1821
}
1922
}

src/NHibernate/Dialect/Oracle8iDialect.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,9 @@ public override JoinFragment CreateOuterJoinFragment()
328328
return new OracleJoinFragment();
329329
}
330330

331+
/// <inheritdoc />
332+
public override bool SupportsCrossJoin => false;
333+
331334
/// <summary>
332335
/// Map case support to the Oracle DECODE function. Oracle did not
333336
/// add support for CASE until 9i.

0 commit comments

Comments
 (0)