diff --git a/src/NHibernate.Test/Async/Criteria/EntityJoinCriteriaTest.cs b/src/NHibernate.Test/Async/Criteria/EntityJoinCriteriaTest.cs
new file mode 100644
index 00000000000..bce97afd549
--- /dev/null
+++ b/src/NHibernate.Test/Async/Criteria/EntityJoinCriteriaTest.cs
@@ -0,0 +1,546 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by AsyncGenerator.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+
+using System;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Criterion;
+using NHibernate.Mapping.ByCode;
+using NHibernate.SqlCommand;
+using NUnit.Framework;
+
+namespace NHibernate.Test.Criteria
+{
+ using System.Threading.Tasks;
+ ///
+ /// Tests for explicit entity joins (not associated entities)
+ ///
+ [TestFixture]
+ public class EntityJoinCriteriaTestAsync : TestCaseMappingByCode
+ {
+ private const string customEntityName = "CustomEntityName";
+ private EntityWithCompositeId _entityWithCompositeId;
+ private EntityWithNoAssociation _noAssociation;
+ private EntityCustomEntityName _entityWithCustomEntityName;
+
+ //check JoinEntityAlias - JoinAlias analog for entity join
+ [Test]
+ public async Task CanJoinNotAssociatedEntityAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex entityComplex = null;
+ EntityWithNoAssociation root = null;
+ root = await (session.QueryOver(() => root)
+ .JoinEntityAlias(() => entityComplex, Restrictions.Where(() => root.Complex1Id == entityComplex.Id)).Take(1)
+ .SingleOrDefaultAsync());
+ entityComplex = await (session.LoadAsync(root.Complex1Id));
+
+ Assert.That(NHibernateUtil.IsInitialized(entityComplex), Is.True);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ //check JoinEntityAlias - JoinAlias analog for entity join
+ [Test]
+ public async Task CanJoinNotAssociatedEntity_ExpressionAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex entityComplex = null;
+ EntityWithNoAssociation root = null;
+ root = await (session.QueryOver(() => root)
+ .JoinEntityAlias(() => entityComplex, () => root.Complex1Id == entityComplex.Id).Take(1)
+ .SingleOrDefaultAsync());
+ entityComplex = await (session.LoadAsync(root.Complex1Id));
+
+ Assert.That(NHibernateUtil.IsInitialized(entityComplex), Is.True);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ //check JoinEntityQueryOver - JoinQueryOver analog for entity join
+ [Test]
+ public async Task CanJoinEntityQueryOverAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex ejQueryOver = null;
+ EntityWithNoAssociation root = null;
+ root = await (session.QueryOver(() => root)
+ .JoinEntityQueryOver(() => ejQueryOver, Restrictions.Where(() => root.Complex1Id == ejQueryOver.Id))
+ .Take(1)
+ .SingleOrDefaultAsync());
+ ejQueryOver = await (session.LoadAsync(root.Complex1Id));
+
+ Assert.That(NHibernateUtil.IsInitialized(ejQueryOver), Is.True);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ //check JoinEntityQueryOver - JoinQueryOver analog for entity join
+ [Test]
+ public async Task CanJoinEntityQueryOver_ExpressionAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex ejQueryOver = null;
+ EntityWithNoAssociation root = null;
+ root = await (session.QueryOver(() => root)
+ .JoinEntityQueryOver(() => ejQueryOver, () => root.Complex1Id == ejQueryOver.Id)
+ .Take(1)
+ .SingleOrDefaultAsync());
+ ejQueryOver = await (session.LoadAsync(root.Complex1Id));
+
+ Assert.That(NHibernateUtil.IsInitialized(ejQueryOver), Is.True);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ //can join not associated entity and join associated entities for it via JoinQueryOver
+ [Test]
+ public async Task CanQueryOverForAssociationInNotAssociatedEntityAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex ejComplex = null;
+ EntityWithNoAssociation root = null;
+ root = await (session.QueryOver(() => root)
+ .JoinEntityQueryOver(() => ejComplex, () => root.Complex1Id == ejComplex.Id)
+ .JoinQueryOver(ej => ej.Child1)
+ .Take(1)
+ .SingleOrDefaultAsync());
+
+ ejComplex = await (session.LoadAsync(root.Complex1Id));
+
+ Assert.That(NHibernateUtil.IsInitialized(ejComplex), Is.True);
+ Assert.That(NHibernateUtil.IsInitialized(ejComplex.Child1), Is.True);
+ Assert.That(NHibernateUtil.IsInitialized(ejComplex.Child2), Is.False);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ [Test]
+ public async Task SimpleProjectionForEntityJoinAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntityComplex ejComplex = null;
+ EntityWithNoAssociation root = null;
+ var name = await (session.QueryOver(() => root)
+ .JoinEntityQueryOver(() => ejComplex, () => root.Complex1Id == ejComplex.Id)
+ .Select((e) => ejComplex.Name)
+ .Take(1)
+ .SingleOrDefaultAsync());
+
+ Assert.That(name, Is.Not.Empty);
+ Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected");
+ }
+ }
+
+ [Test]
+ public async Task EntityProjectionForEntityJoinAsync()
+ {
+ using (var sqlLog = new SqlLogSpy())
+ using (var session = OpenSession())
+ {
+ EntitySimpleChild ejChild1 = null;
+
+ EntityComplex root = null;
+ EntityComplex st = null;
+ var r = await (session
+ .QueryOver(() => root)
+ .JoinAlias(c => c.SameTypeChild, () => st)
+ .JoinEntityAlias(() => ejChild1, () => ejChild1.Id == root.Child1.Id)
+ .Select(
+ Projections.RootEntity(),
+ Projections.Entity(() => st),
+ Projections.Entity(() => ejChild1)
+ )
+ .SingleOrDefaultAsync