Skip to content

Add cross join support for Hql and Linq query provider #2327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 21, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@


using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate.Cache;
using NHibernate.Cfg;
using NHibernate.Hql.Ast.ANTLR;
using NHibernate.Linq;
using NUnit.Framework;
using NUnit.Framework.Constraints;
using Environment = NHibernate.Cfg.Environment;

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

[Test]
public async Task TestHqlCrossJoinFetchFormulaAsync()
{
if (!Dialect.SupportsCrossJoin)
{
Assert.Ignore("Dialect does not support cross join.");
}

var persons = new List<Person>();
var bestFriends = new List<Person>();
using (var sqlSpy = new SqlLogSpy())
using (var s = OpenSession())
{
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[]>());
foreach (var arr in list)
{
persons.Add((Person) arr[0]);
bestFriends.Add((Person) arr[1]);
}
}

AssertPersons(persons, false);
AssertPersons(bestFriends, true);

void AssertPersons(List<Person> results, bool fetched)
{
foreach (var person in results)
{
Assert.That(person, Is.Not.Null);
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Image"), Is.False);
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Address"), Is.False);
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Formula"), fetched ? Is.True : (IResolveConstraint) Is.False);
}
}
}

private static Person GeneratePerson(int i, Person bestFriend)
{
return new Person
Expand Down
21 changes: 21 additions & 0 deletions src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,27 @@ public async Task EntityJoinWithFetchesAsync()
}
}

[Test]
public async Task CrossJoinAndWhereClauseAsync()
{
using (var sqlLog = new SqlLogSpy())
using (var session = OpenSession())
{
var result = await (session.CreateQuery(
"SELECT s " +
"FROM EntityComplex s cross join EntityComplex q " +
"where s.SameTypeChild.Id = q.SameTypeChild.Id"
).ListAsync());

Assert.That(result, Has.Count.EqualTo(1));
Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
if (Dialect.SupportsCrossJoin)
{
Assert.That(sqlLog.GetWholeLog(), Does.Contain("cross join"), "A cross join is expected in the SQL select");
}
}
}

#region Test Setup

protected override HbmMapping GetMappings()
Expand Down
33 changes: 33 additions & 0 deletions src/NHibernate.Test/Async/Linq/ByMethod/JoinTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
//------------------------------------------------------------------------------


using System;
using System.Linq;
using System.Reflection;
using NHibernate.Cfg;
using NHibernate.Engine.Query;
using NHibernate.Util;
using NSubstitute;
using NUnit.Framework;
using NHibernate.Linq;

Expand All @@ -31,5 +37,32 @@ public async Task MultipleLinqJoinsWithSameProjectionNamesAsync()
Assert.That(orders.Count, Is.EqualTo(828));
Assert.IsTrue(orders.All(x => x.FirstId == x.SecondId - 1 && x.SecondId == x.ThirdId - 1));
}

[TestCase(false)]
[TestCase(true)]
public async Task CrossJoinWithPredicateInWhereStatementAsync(bool useCrossJoin)
{
if (useCrossJoin && !Dialect.SupportsCrossJoin)
{
Assert.Ignore("Dialect does not support cross join.");
}

using (var substitute = SubstituteDialect())
using (var sqlSpy = new SqlLogSpy())
{
ClearQueryPlanCache();
substitute.Value.SupportsCrossJoin.Returns(useCrossJoin);

var result = await ((from o in db.Orders
from o2 in db.Orders.Where(x => x.Freight > 50)
where (o.OrderId == o2.OrderId + 1) || (o.OrderId == o2.OrderId - 1)
select new { o.OrderId, OrderId2 = o2.OrderId }).ToListAsync());

var sql = sqlSpy.GetWholeLog();
Assert.That(result.Count, Is.EqualTo(720));
Assert.That(sql, Does.Contain(useCrossJoin ? "cross join" : "inner join"));
Assert.That(GetTotalOccurrences(sql, "inner join"), Is.EqualTo(useCrossJoin ? 0 : 1));
}
}
}
}
Loading