diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs index c6fa377a043..77c3127e73f 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,14 @@ public async Task LinqFetchAsync() } } + [Test(Description = "GH-3239")] + public async Task LinqFetchManyToManyAsync() + { + using var session = OpenSession(); + var result = await (session.Query().Fetch(x => x.RefferedDetailsManyToMany).FirstAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public async Task QueryOverFetchAsync() { @@ -63,6 +73,14 @@ 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() { @@ -73,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)); + } } } 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..a216a4d2357 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,14 @@ public void LinqFetch() } } + [Test(Description = "GH-3239")] + public void LinqFetchManyToMany() + { + using var session = OpenSession(); + var result = session.Query().Fetch(x => x.RefferedDetailsManyToMany).First(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public void QueryOverFetch() { @@ -52,6 +62,14 @@ 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() { @@ -62,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)); + } } } 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 @@ + + + + + + + + + + + + + diff --git a/src/NHibernate/Engine/TableGroupJoinHelper.cs b/src/NHibernate/Engine/TableGroupJoinHelper.cs index 18dddb12dfe..12ad3be28a2 100644 --- a/src/NHibernate/Engine/TableGroupJoinHelper.cs +++ b/src/NHibernate/Engine/TableGroupJoinHelper.cs @@ -68,15 +68,18 @@ private static bool NeedsTableGroupJoin(IReadOnlyList joins, SqlString[] foreach (var join in joins) { - var entityPersister = GetEntityPersister(join.Joinable); + var entityPersister = GetEntityPersister(join.Joinable, out var isManyToMany); if (entityPersister?.HasSubclassJoins(includeSubclasses && isSubclassIncluded(join.Alias)) != true) continue; if (hasWithClause) return true; - if (entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) + if (!isManyToMany // many-to-many keys are stored in separate table + && entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) + { return true; + } } return false; @@ -91,14 +94,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 isManyToMany); 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 || isManyToMany) // 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 +116,14 @@ private static SqlString GetTableGroupJoinWithClause(SqlString[] withClauseFragm return fromFragment.ToSqlString(); } - private static AbstractEntityPersister GetEntityPersister(IJoinable joinable) + private static AbstractEntityPersister GetEntityPersister(IJoinable joinable, out bool isManyToMany) { + isManyToMany = false; if (!joinable.IsCollection) return joinable as AbstractEntityPersister; var collection = (IQueryableCollection) joinable; + isManyToMany = collection.IsManyToMany; return collection.ElementType.IsEntityType ? collection.ElementPersister as AbstractEntityPersister : null; }