diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj
index 4ce9639e5e2..6754961c9c0 100644
--- a/src/NHibernate.Test/NHibernate.Test.csproj
+++ b/src/NHibernate.Test/NHibernate.Test.csproj
@@ -1089,6 +1089,7 @@
+
@@ -1096,6 +1097,7 @@
+
diff --git a/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs b/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs
index eab851b6ff1..418912d8d21 100644
--- a/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs
+++ b/src/NHibernate.Test/Stateless/FetchingLazyCollections/LazyCollectionFetchTests.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Iesi.Collections.Generic;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping.ByCode.Conformist;
+using NHibernate.Linq;
using NUnit.Framework;
using SharpTestsEx;
@@ -130,6 +132,24 @@ public void ShouldWorkLoadingComplexEntities()
tx.Commit();
}
+ using (IStatelessSession s = sessions.OpenStatelessSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ IList> hf = s.Query>().FetchMany(f => f.Childs).ToList();
+ Assert.That(hf.Count, Is.EqualTo(1));
+ Assert.That(hf[0].Father.Name, Is.EqualTo(humanFather));
+ Assert.That(hf[0].Mother.Name, Is.EqualTo(humanMother));
+ NHibernateUtil.IsInitialized(hf[0].Childs).Should("Lazy collection should be initialized").Be.True();
+
+ IList> rf = s.Query>().FetchMany(f => f.Childs).ToList();
+ Assert.That(rf.Count, Is.EqualTo(1));
+ Assert.That(rf[0].Father.Description, Is.EqualTo(crocodileFather));
+ Assert.That(rf[0].Mother.Description, Is.EqualTo(crocodileMother));
+ NHibernateUtil.IsInitialized(hf[0].Childs).Should("Lazy collection should be initialized").Be.True();
+
+ tx.Commit();
+ }
+
using (ISession s = sessions.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
diff --git a/src/NHibernate.Test/Stateless/FetchingLazyCollections/TreeFetchTests.cs b/src/NHibernate.Test/Stateless/FetchingLazyCollections/TreeFetchTests.cs
new file mode 100644
index 00000000000..4ac6b1f9aea
--- /dev/null
+++ b/src/NHibernate.Test/Stateless/FetchingLazyCollections/TreeFetchTests.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Iesi.Collections.Generic;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NHibernate.Mapping.ByCode.Conformist;
+using NHibernate.Linq;
+using NUnit.Framework;
+using SharpTestsEx;
+
+namespace NHibernate.Test.Stateless.FetchingLazyCollections
+{
+ public class TreeFetchTests : TestCaseMappingByCode
+ {
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ModelMapper();
+ mapper.BeforeMapClass += (mi, t, cm) => cm.Id(im => im.Generator(Generators.HighLow));
+ mapper.Class(
+ mc =>
+ {
+ mc.Id(x => x.Id);
+ mc.Property(x => x.Content);
+ mc.Set(x => x.Children, cam =>
+ {
+ cam.Key(km => km.Column("parentId"));
+ cam.Cascade(Mapping.ByCode.Cascade.All);
+ }, rel => rel.OneToMany());
+ });
+ var mappings = mapper.CompileMappingForAllExplicitlyAddedEntities();
+ return mappings;
+ }
+
+ [Test]
+ public void FetchMultipleHierarchies()
+ {
+ using (ISession s = sessions.OpenSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ var root = new TreeNode { Content = "Root" };
+ var child1 = new TreeNode { Content = "Child1" };
+ root.Children.Add(child1);
+ root.Children.Add(new TreeNode { Content = "Child2" });
+ child1.Children.Add(new TreeNode { Content = "Child1Child1" });
+ child1.Children.Add(new TreeNode { Content = "Child1Child2" });
+ s.Save(root);
+ tx.Commit();
+ }
+
+ using (IStatelessSession s = sessions.OpenStatelessSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ IList rootNodes = s.Query().Where(t => t.Content == "Root")
+ .FetchMany(f => f.Children)
+ .ThenFetchMany(f => f.Children).ToList();
+ Assert.That(rootNodes.Count, Is.EqualTo(1));
+ Assert.That(rootNodes.First().Children.Count, Is.EqualTo(2));
+
+ tx.Commit();
+ }
+
+ using (ISession s = sessions.OpenSession())
+ using (ITransaction tx = s.BeginTransaction())
+ {
+ s.Delete("from TreeNode");
+ tx.Commit();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NHibernate.Test/Stateless/TreeNode.cs b/src/NHibernate.Test/Stateless/TreeNode.cs
new file mode 100644
index 00000000000..4c285e9de19
--- /dev/null
+++ b/src/NHibernate.Test/Stateless/TreeNode.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Iesi.Collections.Generic;
+
+namespace NHibernate.Test.Stateless
+{
+ public class TreeNode
+ {
+ private ISet children = new HashedSet();
+
+ public virtual int Id { get; protected set; }
+
+ public virtual string Content { get; set; }
+
+ public virtual ISet Children
+ {
+ get { return children; }
+ protected set { children = value; }
+ }
+ }
+}
diff --git a/src/NHibernate/Impl/StatelessSessionImpl.cs b/src/NHibernate/Impl/StatelessSessionImpl.cs
index e9534b9ba48..1d9c90b60e9 100644
--- a/src/NHibernate/Impl/StatelessSessionImpl.cs
+++ b/src/NHibernate/Impl/StatelessSessionImpl.cs
@@ -356,7 +356,13 @@ public override bool IsEventSource
public override object GetEntityUsingInterceptor(EntityKey key)
{
CheckAndUpdateSessionStatus();
- return null;
+ // while a pending Query we should use existing temporary entities so a join fetch does not create multiple instances
+ // of the same parent item
+ object obj;
+ if (temporaryPersistenceContext.EntitiesByKey.TryGetValue(key, out obj))
+ return obj;
+ else
+ return null;
}
public override IPersistenceContext PersistenceContext