diff --git a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs index dffb019b94b..b9d0531be4f 100644 --- a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs @@ -395,6 +395,23 @@ public void SkipRootEntityIsNotSupportedAsync() } } + [Test] + public async Task OrderedInnerJoinFetchAsync() + { + using (var session = OpenSession()) + { + var list = await (session.QueryOver() + .Where(ec => ec.Id == _parentEntityComplexId) + .JoinQueryOver(c => c.ChildrenList).Fetch(SelectMode.Fetch, child => child) + .TransformUsing(Transformers.DistinctRootEntity) + .ListAsync()); + + var childList = list[0].ChildrenList; + Assert.That(list[0].ChildrenList.Count, Is.GreaterThan(1)); + Assert.That(list[0].ChildrenList, Is.EqualTo(list[0].ChildrenList.OrderByDescending(c => c.OrderIdx)), "wrong order"); + } + } + [Test, Obsolete] public async Task FetchModeEagerForLazyAsync() { @@ -562,7 +579,7 @@ protected override HbmMapping GetMappings() m.Column("SameTypeChildId"); m.ForeignKey("none"); }); - MapList(rc, ep => ep.ChildrenList); + MapList(rc, ep => ep.ChildrenList, mapper: m => m.OrderBy("OrderIdx desc")); MapList(rc, ep => ep.ChildrenListEmpty); }); @@ -570,7 +587,11 @@ protected override HbmMapping GetMappings() mapper, default(EntitySimpleChild), c => c.Children, - rc => { rc.Property(sc => sc.LazyProp, mp => mp.Lazy(true)); }); + rc => + { + rc.Property(sc => sc.LazyProp, mp => mp.Lazy(true)); + rc.Property(sc => sc.OrderIdx); + }); MapSimpleChild(mapper, default(Level2Child), c => c.Children); MapSimpleChild(mapper); @@ -598,7 +619,7 @@ private static void MapSimpleChild(ModelMapper mapper, TChild }); } - private static void MapList(IClassMapper rc, Expression>> expression, CollectionFetchMode fetchMode = null) where TParent : class + private static void MapList(IClassMapper rc, Expression>> expression, CollectionFetchMode fetchMode = null, Action> mapper = null) where TParent : class { rc.Bag( expression, @@ -620,6 +641,7 @@ private static void MapList(IClassMapper rc, Express { m.Fetch(fetchMode); } + mapper?.Invoke(m); }, a => a.OneToMany()); } @@ -682,7 +704,8 @@ protected override void OnSetUp() }, } } - } + }, + OrderIdx = 100 }; var child2 = new EntitySimpleChild @@ -691,6 +714,17 @@ protected override void OnSetUp() LazyProp = "LazyFromSimpleChild2", }; + var child3 = new EntitySimpleChild + { + Name = "Child3", + OrderIdx = 0 + }; + var child4 = new EntitySimpleChild + { + Name = "Child4", + OrderIdx = 50 + }; + var parent = new EntityComplex { Name = "ComplexEntityParent", @@ -701,7 +735,7 @@ protected override void OnSetUp() { Name = "ComplexEntityChild" }, - ChildrenList = new List {child1}, + ChildrenList = new List {child3, child1, child4 }, ChildrenListEmpty = new List { }, }; session.Save(new EntityEager() diff --git a/src/NHibernate.Test/Criteria/SelectModeTest/Entities.cs b/src/NHibernate.Test/Criteria/SelectModeTest/Entities.cs index a38f94e0bfc..25732c89496 100644 --- a/src/NHibernate.Test/Criteria/SelectModeTest/Entities.cs +++ b/src/NHibernate.Test/Criteria/SelectModeTest/Entities.cs @@ -43,6 +43,7 @@ public class EntitySimpleChild : BaseChild { public virtual IList Children { get; set; } = new List(); public virtual string LazyProp { get; set; } + public virtual int OrderIdx { get; set; } } public class Level2Child : BaseChild diff --git a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs index 57c40a22f74..595fa87baba 100644 --- a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs @@ -426,6 +426,23 @@ public void SkipRootEntityIsNotSupported() } } + [Test] + public void OrderedInnerJoinFetch() + { + using (var session = OpenSession()) + { + var list = session.QueryOver() + .Where(ec => ec.Id == _parentEntityComplexId) + .JoinQueryOver(c => c.ChildrenList).Fetch(SelectMode.Fetch, child => child) + .TransformUsing(Transformers.DistinctRootEntity) + .List(); + + var childList = list[0].ChildrenList; + Assert.That(list[0].ChildrenList.Count, Is.GreaterThan(1)); + Assert.That(list[0].ChildrenList, Is.EqualTo(list[0].ChildrenList.OrderByDescending(c => c.OrderIdx)), "wrong order"); + } + } + [Test, Obsolete] public void FetchModeEagerForLazy() { @@ -593,7 +610,7 @@ protected override HbmMapping GetMappings() m.Column("SameTypeChildId"); m.ForeignKey("none"); }); - MapList(rc, ep => ep.ChildrenList); + MapList(rc, ep => ep.ChildrenList, mapper: m => m.OrderBy("OrderIdx desc")); MapList(rc, ep => ep.ChildrenListEmpty); }); @@ -601,7 +618,11 @@ protected override HbmMapping GetMappings() mapper, default(EntitySimpleChild), c => c.Children, - rc => { rc.Property(sc => sc.LazyProp, mp => mp.Lazy(true)); }); + rc => + { + rc.Property(sc => sc.LazyProp, mp => mp.Lazy(true)); + rc.Property(sc => sc.OrderIdx); + }); MapSimpleChild(mapper, default(Level2Child), c => c.Children); MapSimpleChild(mapper); @@ -629,7 +650,7 @@ private static void MapSimpleChild(ModelMapper mapper, TChild }); } - private static void MapList(IClassMapper rc, Expression>> expression, CollectionFetchMode fetchMode = null) where TParent : class + private static void MapList(IClassMapper rc, Expression>> expression, CollectionFetchMode fetchMode = null, Action> mapper = null) where TParent : class { rc.Bag( expression, @@ -651,6 +672,7 @@ private static void MapList(IClassMapper rc, Express { m.Fetch(fetchMode); } + mapper?.Invoke(m); }, a => a.OneToMany()); } @@ -713,7 +735,8 @@ protected override void OnSetUp() }, } } - } + }, + OrderIdx = 100 }; var child2 = new EntitySimpleChild @@ -722,6 +745,17 @@ protected override void OnSetUp() LazyProp = "LazyFromSimpleChild2", }; + var child3 = new EntitySimpleChild + { + Name = "Child3", + OrderIdx = 0 + }; + var child4 = new EntitySimpleChild + { + Name = "Child4", + OrderIdx = 50 + }; + var parent = new EntityComplex { Name = "ComplexEntityParent", @@ -732,7 +766,7 @@ protected override void OnSetUp() { Name = "ComplexEntityChild" }, - ChildrenList = new List {child1}, + ChildrenList = new List {child3, child1, child4 }, ChildrenListEmpty = new List { }, }; session.Save(new EntityEager() diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index 56a3fc425e6..d65520a03e1 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -882,32 +882,26 @@ protected SqlString OrderBy(IList associations) OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in associations) { - if (oj.JoinType == JoinType.LeftOuterJoin) + if (oj.ShouldFetchCollectionPersister()) { - if (oj.Joinable.IsCollection) + IQueryableCollection queryableCollection = (IQueryableCollection) oj.Joinable; + if (queryableCollection.HasOrdering) { - IQueryableCollection queryableCollection = (IQueryableCollection)oj.Joinable; - if (queryableCollection.HasOrdering) - { - string orderByString = queryableCollection.GetSQLOrderByString(oj.RHSAlias); - buf.Add(orderByString).Add(StringHelper.CommaSpace); - } + string orderByString = queryableCollection.GetSQLOrderByString(oj.RHSAlias); + buf.Add(orderByString).Add(StringHelper.CommaSpace); } - else + } + else if (!oj.IsCollection && last?.ShouldFetchCollectionPersister() == true) + { + // it might still need to apply a collection ordering based on a + // many-to-many defined order-by... + IQueryableCollection queryableCollection = (IQueryableCollection) last.Joinable; + if (queryableCollection.IsManyToMany && last.IsManyToManyWith(oj)) { - // it might still need to apply a collection ordering based on a - // many-to-many defined order-by... - if (last != null && last.Joinable.IsCollection) + if (queryableCollection.HasManyToManyOrdering) { - IQueryableCollection queryableCollection = (IQueryableCollection)last.Joinable; - if (queryableCollection.IsManyToMany && last.IsManyToManyWith(oj)) - { - if (queryableCollection.HasManyToManyOrdering) - { - string orderByString = queryableCollection.GetManyToManyOrderByString(oj.RHSAlias); - buf.Add(orderByString).Add(StringHelper.CommaSpace); - } - } + string orderByString = queryableCollection.GetManyToManyOrderByString(oj.RHSAlias); + buf.Add(orderByString).Add(StringHelper.CommaSpace); } } }