From 02c8e19889e6d6d37c61a41755e704e3d588c7e3 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 12 Mar 2023 12:38:10 +0200 Subject: [PATCH 1/7] Fix fetching many-to-many with subclasses Test case --- .../NHSpecificTest/NH2174/Entity.cs | 1 + .../NHSpecificTest/NH2174/Fixture.cs | 26 ++++++++++++++++++- .../NHSpecificTest/NH2174/Mappings.hbm.xml | 13 ++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs index d3c4702ac69..2b9ea9bfd4f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs @@ -86,6 +86,7 @@ public override int GetHashCode() private int _id_Doc; private int _id_base; public virtual IList RefferedDetails { get; set; } = new List(); + public virtual IList RefferedDetailsManyToMany { get; set; } = new List(); public int Id_Doc { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs index 13d9922c9d2..e17d6e64041 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs @@ -14,8 +14,10 @@ protected override void OnSetUp() { var doc = new Document {Id_Base = 1, Id_Doc = 2}; session.Save(doc); - session.Save(new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}); + var detail = new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}; + session.Save(detail); + doc.RefferedDetailsManyToMany.Add(detail); transaction.Commit(); } } @@ -42,6 +44,18 @@ public void LinqFetch() } } + [Test(Description = "GH-3239")] + public void LinqFetchManyToMany() + { + using (var session = OpenSession()) + { + var result = (from e in session.Query().Fetch(x => x.RefferedDetailsManyToMany) + select e).FirstOrDefault(); + + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + } + [Test] public void QueryOverFetch() { @@ -52,6 +66,16 @@ public void QueryOverFetch() } } + [Test(Description = "GH-3239")] + public void QueryOverFetchManyToMany() + { + using (var session = OpenSession()) + { + var result = session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefault(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + } + [Test] public void LazyLoad() { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml index b6b056c2f80..d04459f0265 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml @@ -42,5 +42,18 @@ + + + + + + + + + + + + + From c6ad640ac09b3e102a8d82888f348bdaadcccbd2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Mar 2023 10:42:21 +0000 Subject: [PATCH 2/7] Generate async files --- .../Async/NHSpecificTest/NH2174/Fixture.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs index c6fa377a043..d411d32395d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs @@ -25,8 +25,10 @@ protected override void OnSetUp() { var doc = new Document {Id_Base = 1, Id_Doc = 2}; session.Save(doc); - session.Save(new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}); + var detail = new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}; + session.Save(detail); + doc.RefferedDetailsManyToMany.Add(detail); transaction.Commit(); } } @@ -53,6 +55,18 @@ public async Task LinqFetchAsync() } } + [Test(Description = "GH-3239")] + public async Task LinqFetchManyToManyAsync() + { + using (var session = OpenSession()) + { + var result = await ((from e in session.Query().Fetch(x => x.RefferedDetailsManyToMany) + select e).FirstOrDefaultAsync()); + + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + } + [Test] public async Task QueryOverFetchAsync() { @@ -63,6 +77,16 @@ public async Task QueryOverFetchAsync() } } + [Test(Description = "GH-3239")] + public async Task QueryOverFetchManyToManyAsync() + { + using (var session = OpenSession()) + { + var result = await (session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefaultAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + } + [Test] public async Task LazyLoadAsync() { From 1c190113d6d441ca09121e66638790d17238fed2 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 12 Mar 2023 12:50:09 +0200 Subject: [PATCH 3/7] Fix --- src/NHibernate/Engine/TableGroupJoinHelper.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 18dddb12dfe..0f3ca315a78 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -68,14 +68,15 @@ private static bool NeedsTableGroupJoin(IReadOnlyList joins, SqlString[] foreach (var join in joins) { - var entityPersister = GetEntityPersister(join.Joinable); + var entityPersister = GetEntityPersister(join.Joinable, out var collection); if (entityPersister?.HasSubclassJoins(includeSubclasses && isSubclassIncluded(join.Alias)) != true) continue; if (hasWithClause) return true; - if (entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) + if (collection?.IsManyToMany != true // many-to-many keys are stored in separate table + && entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) return true; } @@ -91,14 +92,16 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm var isAssociationJoin = lhsColumns.Length > 0; if (isAssociationJoin) { - var entityPersister = GetEntityPersister(first.Joinable); + var entityPersister = GetEntityPersister(first.Joinable, out var collection); string rhsAlias = first.Alias; string[] rhsColumns = first.RHSColumns; for (int j = 0; j < lhsColumns.Length; j++) { fromFragment.Add(lhsColumns[j]) .Add("=") - .Add(entityPersister?.GenerateTableAliasForColumn(rhsAlias, rhsColumns[j]) ?? rhsAlias) + .Add(entityPersister == null || collection?.IsManyToMany == true // many-to-many keys are stored in separate table + ? rhsAlias + : entityPersister.GenerateTableAliasForColumn(rhsAlias, rhsColumns[j])) .Add(".") .Add(rhsColumns[j]); if (j != lhsColumns.Length - 1) @@ -111,12 +114,13 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm return fromFragment.ToSqlString(); } - private static AbstractEntityPersister GetEntityPersister(IJoinable joinable) + private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out IQueryableCollection collection) { + collection = null; if (!joinable.IsCollection) return joinable as AbstractEntityPersister; - var collection = (IQueryableCollection) joinable; + collection = (IQueryableCollection) joinable; return collection.ElementType.IsEntityType ? collection.ElementPersister as AbstractEntityPersister : null; } From 2cb430e0bdaa3d87424867714660e2ef8ba93bdf Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 12 Mar 2023 16:12:31 +0200 Subject: [PATCH 4/7] One more test case --- .../NHSpecificTest/NH2174/Fixture.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs index e17d6e64041..a216a4d2357 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs @@ -47,13 +47,9 @@ public void LinqFetch() [Test(Description = "GH-3239")] public void LinqFetchManyToMany() { - using (var session = OpenSession()) - { - var result = (from e in session.Query().Fetch(x => x.RefferedDetailsManyToMany) - select e).FirstOrDefault(); - - Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + var result = session.Query().Fetch(x => x.RefferedDetailsManyToMany).First(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); } [Test] @@ -69,11 +65,9 @@ public void QueryOverFetch() [Test(Description = "GH-3239")] public void QueryOverFetchManyToMany() { - using (var session = OpenSession()) - { - var result = session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefault(); - Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + var result = session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefault(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); } [Test] @@ -86,5 +80,13 @@ public void LazyLoad() Assert.That(result.RefferedDetails.Count, Is.EqualTo(1)); } } + + [Test] + public void LazyLoadManyToMany() + { + using var session = OpenSession(); + var result = session.Query().First(); + Assert.That(result.RefferedDetailsManyToMany.Count, Is.EqualTo(1)); + } } } From c646b2d1227d85b8e712517202d78651ea0be1a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Mar 2023 14:16:57 +0000 Subject: [PATCH 5/7] Generate async files --- .../Async/NHSpecificTest/NH2174/Fixture.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs index d411d32395d..77c3127e73f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs @@ -58,13 +58,9 @@ public async Task LinqFetchAsync() [Test(Description = "GH-3239")] public async Task LinqFetchManyToManyAsync() { - using (var session = OpenSession()) - { - var result = await ((from e in session.Query().Fetch(x => x.RefferedDetailsManyToMany) - select e).FirstOrDefaultAsync()); - - Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + var result = await (session.Query().Fetch(x => x.RefferedDetailsManyToMany).FirstAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); } [Test] @@ -80,11 +76,9 @@ public async Task QueryOverFetchAsync() [Test(Description = "GH-3239")] public async Task QueryOverFetchManyToManyAsync() { - using (var session = OpenSession()) - { - var result = await (session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefaultAsync()); - Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + var result = await (session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefaultAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); } [Test] @@ -97,5 +91,13 @@ public async Task LazyLoadAsync() Assert.That(result.RefferedDetails.Count, Is.EqualTo(1)); } } + + [Test] + public async Task LazyLoadManyToManyAsync() + { + using var session = OpenSession(); + var result = await (session.Query().FirstAsync()); + Assert.That(result.RefferedDetailsManyToMany.Count, Is.EqualTo(1)); + } } } From a38c0ab17943b2b5d652d2c42e5b2dd40e1e3e63 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Mon, 13 Mar 2023 08:48:06 +0200 Subject: [PATCH 6/7] code review --- src/NHibernate/Engine/TableGroupJoinHelper.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 0f3ca315a78..29de0592ca9 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -68,14 +68,14 @@ private static bool NeedsTableGroupJoin(IReadOnlyList joins, SqlString[] foreach (var join in joins) { - var entityPersister = GetEntityPersister(join.Joinable, out var collection); + var entityPersister = GetEntityPersister(join.Joinable, out var isManyToMany); if (entityPersister?.HasSubclassJoins(includeSubclasses && isSubclassIncluded(join.Alias)) != true) continue; if (hasWithClause) return true; - if (collection?.IsManyToMany != true // many-to-many keys are stored in separate table + if (!isManyToMany // many-to-many keys are stored in separate table && entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) return true; } @@ -92,14 +92,14 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm var isAssociationJoin = lhsColumns.Length > 0; if (isAssociationJoin) { - var entityPersister = GetEntityPersister(first.Joinable, out var collection); + var entityPersister = GetEntityPersister(first.Joinable, out var isManyToMany); string rhsAlias = first.Alias; string[] rhsColumns = first.RHSColumns; for (int j = 0; j < lhsColumns.Length; j++) { fromFragment.Add(lhsColumns[j]) .Add("=") - .Add(entityPersister == null || collection?.IsManyToMany == true // many-to-many keys are stored in separate table + .Add((entityPersister == null || isManyToMany) // many-to-many keys are stored in separate table ? rhsAlias : entityPersister.GenerateTableAliasForColumn(rhsAlias, rhsColumns[j])) .Add(".") @@ -114,13 +114,14 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm return fromFragment.ToSqlString(); } - private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out IQueryableCollection collection) + private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out bool isManyToMany) { - collection = null; + isManyToMany = false; if (!joinable.IsCollection) return joinable as AbstractEntityPersister; - collection = (IQueryableCollection) joinable; + var collection = (IQueryableCollection) joinable; + isManyToMany = collection.IsManyToMany; return collection.ElementType.IsEntityType ? collection.ElementPersister as AbstractEntityPersister : null; } From 2442bd321624ccd65eaca76e2ef6aa99aa51cb11 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Mon, 13 Mar 2023 10:47:42 +0200 Subject: [PATCH 7/7] Update src/NHibernate/Engine/TableGroupJoinHelper.cs Co-authored-by: Alex Zaytsev --- src/NHibernate/Engine/TableGroupJoinHelper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 29de0592ca9..12ad3be28a2 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -77,7 +77,9 @@ private static bool NeedsTableGroupJoin(IReadOnlyList joins, SqlString[] if (!isManyToMany // many-to-many keys are stored in separate table && entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) + { return true; + } } return false;