diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs
new file mode 100644
index 00000000000..1ca210a186e
--- /dev/null
+++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs
@@ -0,0 +1,123 @@
+//------------------------------------------------------------------------------
+//
+// 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 System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NHibernate.Linq;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.GH3317
+{
+ using System.Threading.Tasks;
+ [TestFixture(true)]
+ [TestFixture(false)]
+ public class ComponentsListFixtureAsync : TestCaseMappingByCode
+ {
+ private readonly bool _fetchJoinMapping;
+ private Guid _id;
+
+ public ComponentsListFixtureAsync(bool fetchJoinMapping)
+ {
+ _fetchJoinMapping = fetchJoinMapping;
+ }
+
+ protected override void OnSetUp()
+ {
+ using var session = OpenSession();
+ using var tr = session.BeginTransaction();
+ var root = new Entity();
+ root.Entries.Add(new ComponentListEntry { ComponentReference = null, DummyString = "one", });
+
+ session.Save(root);
+ tr.Commit();
+ _id = root.Id;
+ }
+
+ [Test]
+ public async Task LazyLoadingAsync()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = await (newSession.GetAsync(_id));
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ [Test]
+ public async Task QueryOverFetchAsync()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = await (newSession.QueryOver()
+ .Fetch(SelectMode.Fetch, x => x.Entries)
+ .Where(x => x.Id == _id)
+ .SingleOrDefaultAsync());
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ [Test]
+ public async Task LinqFetchAsync()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = await (newSession.Query()
+ .Fetch(x => x.Entries)
+ .Where(x => x.Id == _id)
+ .SingleOrDefaultAsync());
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ protected override void OnTearDown()
+ {
+ using var session = OpenSession();
+ using var transaction = session.BeginTransaction();
+ session.CreateSQLQuery("delete from Entries").ExecuteUpdate();
+ session.Delete("from System.Object");
+ transaction.Commit();
+ }
+
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ModelMapper();
+
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.Property(x => x.Name);
+
+ rc.Bag(
+ x => x.Entries,
+ v =>
+ {
+ if (_fetchJoinMapping)
+ v.Fetch(CollectionFetchMode.Join);
+ },
+ h => h.Component(cmp =>
+ {
+ cmp.Property(x => x.DummyString);
+ cmp.ManyToOne(x => x.ComponentReference);
+ }));
+ });
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.ManyToOne(x => x.Parent, m => m.NotNullable(true));
+ });
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.Property(x => x.Name);
+ });
+
+ return mapper.CompileMappingForAllExplicitlyAddedEntities();
+ }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs
new file mode 100644
index 00000000000..1e43d5554c1
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.GH3317
+{
+ public class Entity
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ public IList Entries { get; set; } = new List();
+ }
+
+ public class ComponentListEntry
+ {
+ public string DummyString { get; set; }
+ public EntityWithParent ComponentReference { get; set; }
+ }
+
+ public class EntityWithParent
+ {
+ public Guid Id { get; set; }
+ public ParentEntity Parent { get; set; }
+ }
+
+ public class ParentEntity
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ }
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs
new file mode 100644
index 00000000000..3847af79449
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NHibernate.Linq;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.GH3317
+{
+ [TestFixture(true)]
+ [TestFixture(false)]
+ public class ComponentsListFixture : TestCaseMappingByCode
+ {
+ private readonly bool _fetchJoinMapping;
+ private Guid _id;
+
+ public ComponentsListFixture(bool fetchJoinMapping)
+ {
+ _fetchJoinMapping = fetchJoinMapping;
+ }
+
+ protected override void OnSetUp()
+ {
+ using var session = OpenSession();
+ using var tr = session.BeginTransaction();
+ var root = new Entity();
+ root.Entries.Add(new ComponentListEntry { ComponentReference = null, DummyString = "one", });
+
+ session.Save(root);
+ tr.Commit();
+ _id = root.Id;
+ }
+
+ [Test]
+ public void LazyLoading()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = newSession.Get(_id);
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ [Test]
+ public void QueryOverFetch()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = newSession.QueryOver()
+ .Fetch(SelectMode.Fetch, x => x.Entries)
+ .Where(x => x.Id == _id)
+ .SingleOrDefault();
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ [Test]
+ public void LinqFetch()
+ {
+ using var newSession = OpenSession();
+ var reloadedRoot = newSession.Query()
+ .Fetch(x => x.Entries)
+ .Where(x => x.Id == _id)
+ .SingleOrDefault();
+ Assert.AreEqual(1, reloadedRoot.Entries.Count);
+ }
+
+ protected override void OnTearDown()
+ {
+ using var session = OpenSession();
+ using var transaction = session.BeginTransaction();
+ session.CreateSQLQuery("delete from Entries").ExecuteUpdate();
+ session.Delete("from System.Object");
+ transaction.Commit();
+ }
+
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ModelMapper();
+
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.Property(x => x.Name);
+
+ rc.Bag(
+ x => x.Entries,
+ v =>
+ {
+ if (_fetchJoinMapping)
+ v.Fetch(CollectionFetchMode.Join);
+ },
+ h => h.Component(cmp =>
+ {
+ cmp.Property(x => x.DummyString);
+ cmp.ManyToOne(x => x.ComponentReference);
+ }));
+ });
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.ManyToOne(x => x.Parent, m => m.NotNullable(true));
+ });
+ mapper.Class(rc =>
+ {
+ rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb));
+ rc.Lazy(false);
+ rc.Property(x => x.Name);
+ });
+
+ return mapper.CompileMappingForAllExplicitlyAddedEntities();
+ }
+ }
+}
diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs
index 65d7594395c..e2650582718 100644
--- a/src/NHibernate/Loader/JoinWalker.cs
+++ b/src/NHibernate/Loader/JoinWalker.cs
@@ -375,6 +375,7 @@ private void WalkCollectionTree(IQueryableCollection persister, string alias, st
}
else if (type.IsComponentType)
{
+ _joinQueue.Enqueue(NextLevelJoinQueueEntry.Instance);
WalkCompositeElementTree(
(IAbstractComponentType) type,
persister.ElementColumnNames,