diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2463/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2463/Fixture.cs index be3772785b3..777e74491ce 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2463/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2463/Fixture.cs @@ -9,6 +9,7 @@ using System.Linq; +using NHibernate.Criterion; using NHibernate.DomainModel; using NUnit.Framework; using NHibernate.Linq; @@ -19,23 +20,68 @@ namespace NHibernate.Test.NHSpecificTest.GH2463 [TestFixture] public class FixtureAsync : TestCase { + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return Dialect.SupportsScalarSubSelects; + } + protected override string[] Mappings { get { return new[] {"ABC.hbm.xml"}; } } + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var a = new A {Name = "A", AnotherName = "X"}; + session.Save(a); + + var b = new B {Name = "B", AnotherName = "X"}; + session.Save(b); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + //Also see GH-2599 [Test] - public async Task CanJoinOnEntityWithDiscriminatorAsync() + public async Task CanJoinOnEntityWithDiscriminatorLinqAsync() { using (var s = OpenSession()) { - await (s.Query().Join( - s.Query(), - a => a.Id, - b => b.Id, + var list = await (s.Query().Join( + s.Query(), + a => a.AnotherName, + b => b.AnotherName, (a, b) => new {a, b}).ToListAsync()); } } + + [Test] + public async Task CanJoinOnEntityWithDiscriminatorQueryOverAsync() + { + using (var s = OpenSession()) + { + A a = null; + B b = null; + var list = await (s.QueryOver(() => a) + .JoinEntityAlias(() => b, () => a.AnotherName == b.AnotherName) + .Select((x) => a.AsEntity(), (x) => b.AsEntity()).ListAsync()); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH2463/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2463/Fixture.cs index 3c18a008262..c8253b90014 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2463/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2463/Fixture.cs @@ -1,4 +1,5 @@ using System.Linq; +using NHibernate.Criterion; using NHibernate.DomainModel; using NUnit.Framework; @@ -7,23 +8,68 @@ namespace NHibernate.Test.NHSpecificTest.GH2463 [TestFixture] public class Fixture : TestCase { + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return Dialect.SupportsScalarSubSelects; + } + protected override string[] Mappings { get { return new[] {"ABC.hbm.xml"}; } } + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var a = new A {Name = "A", AnotherName = "X"}; + session.Save(a); + + var b = new B {Name = "B", AnotherName = "X"}; + session.Save(b); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + //Also see GH-2599 [Test] - public void CanJoinOnEntityWithDiscriminator() + public void CanJoinOnEntityWithDiscriminatorLinq() { using (var s = OpenSession()) { - s.Query().Join( - s.Query(), - a => a.Id, - b => b.Id, + var list = s.Query().Join( + s.Query(), + a => a.AnotherName, + b => b.AnotherName, (a, b) => new {a, b}).ToList(); } } + + [Test] + public void CanJoinOnEntityWithDiscriminatorQueryOver() + { + using (var s = OpenSession()) + { + A a = null; + B b = null; + var list = s.QueryOver(() => a) + .JoinEntityAlias(() => b, () => a.AnotherName == b.AnotherName) + .Select((x) => a.AsEntity(), (x) => b.AsEntity()).List(); + } + } } } diff --git a/src/NHibernate/Engine/JoinSequence.cs b/src/NHibernate/Engine/JoinSequence.cs index ddd68a3dd17..009b3706141 100644 --- a/src/NHibernate/Engine/JoinSequence.cs +++ b/src/NHibernate/Engine/JoinSequence.cs @@ -193,9 +193,9 @@ internal virtual JoinFragment ToJoinFragment( else { // NH Different behavior : NH1179 and NH1293 - // Apply filters in Many-To-One association + // Apply filters for entity joins and Many-To-One association var enabledForManyToOne = FilterHelper.GetEnabledForManyToOne(enabledFilters); - condition = new SqlString(string.IsNullOrEmpty(on) && enabledForManyToOne.Count > 0 + condition = new SqlString(string.IsNullOrEmpty(on) && (ForceFilter || enabledForManyToOne.Count > 0) ? join.Joinable.FilterFragment(join.Alias, enabledForManyToOne) : on); } @@ -327,5 +327,7 @@ public interface ISelector internal string RootAlias => rootAlias; public ISessionFactoryImplementor Factory => factory; + + internal bool ForceFilter { get; set; } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index 4458d5cecce..c534aa5c6be 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -18,7 +18,7 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias); //NH Specific: hibernate uses special class EntityJoinJoinSequenceImpl - JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) + JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) {ForceFilter = true} .AddJoin(entityType, tableAlias, joinType, Array.Empty()); fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index feec3ae674f..1f1ed70fc56 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -388,7 +388,8 @@ internal void AddExplicitEntityJoinAssociation( GetWithClause(path, pathAlias), Factory, enabledFilters, - GetSelectMode(path)), path); + GetSelectMode(path)) {ForceFilter = true}, + path); AddAssociation(assoc); } @@ -851,8 +852,8 @@ protected JoinFragment MergeOuterJoins(IList associati { oj.AddJoins(outerjoin); // NH Different behavior : NH1179 and NH1293 - // Apply filters in Many-To-One association - if (enabledFiltersForManyToOne.Count > 0) + // Apply filters for entity joins and Many-To-One associations + if (oj.ForceFilter || enabledFiltersForManyToOne.Count > 0) { string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne); bool joinClauseDoesNotContainsFilterAlready = diff --git a/src/NHibernate/Loader/OuterJoinableAssociation.cs b/src/NHibernate/Loader/OuterJoinableAssociation.cs index 8e3d680240f..4f50cbfaf3c 100644 --- a/src/NHibernate/Loader/OuterJoinableAssociation.cs +++ b/src/NHibernate/Loader/OuterJoinableAssociation.cs @@ -100,6 +100,8 @@ public SelectMode SelectMode public ISet EntityFetchLazyProperties { get; set; } + internal bool ForceFilter { get; set; } + public int GetOwner(IList associations) { if (IsEntityType || IsCollection)