From f257331fc439132b07b8172f5b39fd2712cd1bca Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 17 Sep 2020 17:33:44 +0300 Subject: [PATCH 1/5] Apply filters for entity joins --- .../Async/NHSpecificTest/GH2549/Fixture.cs | 64 +++++++++++++++++++ .../NHSpecificTest/GH2549/Fixture.cs | 52 +++++++++++++++ .../NHSpecificTest/GH2549/Mappings.hbm.xml | 26 ++++++++ .../NHSpecificTest/GH2549/Model.cs | 15 +++++ .../Ast/ANTLR/Tree/EntityJoinFromElement.cs | 1 - .../ANTLR/Tree/EntityJoinJoinSequenceImpl.cs | 40 +----------- 6 files changed, 159 insertions(+), 39 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2549/Mappings.hbm.xml create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2549/Model.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs new file mode 100644 index 00000000000..a5a39d6b58e --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH2549 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Save(new Person {Id = 1, Name = "Name"}); + s.Save(new Customer {Deleted = false, Name = "Name", Id = 1}); + s.Save(new Customer {Deleted = true, Name = "Name", Id = 2}); + + t.Commit(); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.CreateQuery("delete from System.Object").ExecuteUpdate(); + t.Commit(); + } + } + + [Test] + public async Task EntityJoinFilterAsync() + { + using (var s = OpenSession()) + { + var list = await ((from p in s.Query() + join c in s.Query() on p.Name equals c.Name + select p).ToListAsync()); + + s.EnableFilter("DeletedCustomer").SetParameter("deleted", false); + + var filteredList = await ((from p in s.Query() + join c in s.Query() on p.Name equals c.Name + select p).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(2)); + Assert.That(filteredList, Has.Count.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs new file mode 100644 index 00000000000..f30eed4bef8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs @@ -0,0 +1,52 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH2549 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Save(new Person {Id = 1, Name = "Name"}); + s.Save(new Customer {Deleted = false, Name = "Name", Id = 1}); + s.Save(new Customer {Deleted = true, Name = "Name", Id = 2}); + + t.Commit(); + } + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.CreateQuery("delete from System.Object").ExecuteUpdate(); + t.Commit(); + } + } + + [Test] + public void EntityJoinFilter() + { + using (var s = OpenSession()) + { + var list = (from p in s.Query() + join c in s.Query() on p.Name equals c.Name + select p).ToList(); + + s.EnableFilter("DeletedCustomer").SetParameter("deleted", false); + + var filteredList = (from p in s.Query() + join c in s.Query() on p.Name equals c.Name + select p).ToList(); + + Assert.That(list, Has.Count.EqualTo(2)); + Assert.That(filteredList, Has.Count.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH2549/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH2549/Mappings.hbm.xml new file mode 100644 index 00000000000..65b540b9202 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH2549/Mappings.hbm.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH2549/Model.cs b/src/NHibernate.Test/NHSpecificTest/GH2549/Model.cs new file mode 100644 index 00000000000..b6d678c7b20 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH2549/Model.cs @@ -0,0 +1,15 @@ +namespace NHibernate.Test.NHSpecificTest.GH2549 +{ + public class Customer + { + public virtual int Id { get; set; } + public virtual bool Deleted { get; set; } + public virtual string Name { get; set; } + } + + public class Person + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index e2f4ce33365..acb6b2b81db 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -18,7 +18,6 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, JoinSequence = new EntityJoinJoinSequenceImpl( SessionFactoryHelper.Factory, entityType, - entityPersister.TableName, tableAlias, joinType); diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs index 430515223d0..e2bfa155dad 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using NHibernate.Engine; using NHibernate.SqlCommand; using NHibernate.Type; @@ -8,44 +7,9 @@ namespace NHibernate.Hql.Ast.ANTLR.Tree { class EntityJoinJoinSequenceImpl : JoinSequence { - private readonly EntityType _entityType; - private readonly string _tableName; - private readonly string _tableAlias; - private readonly JoinType _joinType; - - public EntityJoinJoinSequenceImpl(ISessionFactoryImplementor factory, EntityType entityType, string tableName, string tableAlias, JoinType joinType):base(factory) + public EntityJoinJoinSequenceImpl(ISessionFactoryImplementor factory, EntityType entityType, string tableAlias, JoinType joinType):base(factory) { - _entityType = entityType; - _tableName = tableName; - _tableAlias = tableAlias; - _joinType = joinType; - } - - internal override JoinFragment ToJoinFragment( - IDictionary enabledFilters, - bool includeExtraJoins, - SqlString withClauseFragment, - string withClauseJoinAlias, - string withRootAlias) - { - var joinFragment = new ANSIJoinFragment(); - - var on = withClauseFragment ?? SqlString.Empty; - //Note: filters logic commented due to following issues - //1) Original code is non functional as SqlString is immutable and so all Append results are lost. Correct code would look like: on = on.Append(filters); - //2) Also it seems GetOnCondition always returns empty string for entity join (as IsReferenceToPrimaryKey is always true). - // So if filters for entity join really make sense we need to inline GetOnCondition part that retrieves filters -// var filters = _entityType.GetOnCondition(_tableAlias, Factory, enabledFilters); -// if (!string.IsNullOrEmpty(filters)) -// { -// on.Append(" and ").Append(filters); -// } - joinFragment.AddJoin(_tableName, _tableAlias, Array.Empty(), Array.Empty(), _joinType, on); - if (includeExtraJoins) - { - AddExtraJoins(joinFragment, _tableAlias, _entityType.GetAssociatedJoinable(Factory), _joinType == JoinType.InnerJoin); - } - return joinFragment; + AddJoin(entityType, tableAlias, joinType, Array.Empty()); } } } From adba14a7387a4500105b4adac8821441f759c5d2 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 17 Sep 2020 18:58:54 +0300 Subject: [PATCH 2/5] Added test for QueryOver --- .../Async/NHSpecificTest/GH2549/Fixture.cs | 20 ++++++++++++++++++- .../NHSpecificTest/GH2549/Fixture.cs | 20 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs index a5a39d6b58e..82227867203 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2549/Fixture.cs @@ -42,7 +42,7 @@ protected override void OnTearDown() } [Test] - public async Task EntityJoinFilterAsync() + public async Task EntityJoinFilterLinqAsync() { using (var s = OpenSession()) { @@ -60,5 +60,23 @@ join c in s.Query() on p.Name equals c.Name Assert.That(filteredList, Has.Count.EqualTo(1)); } } + + [Test] + public async Task EntityJoinFilterQueryOverAsync() + { + using (var s = OpenSession()) + { + Customer c = null; + Person p = null; + var list = await (s.QueryOver(() => p).JoinEntityAlias(() => c, () => c.Name == p.Name).ListAsync()); + + s.EnableFilter("DeletedCustomer").SetParameter("deleted", false); + + var filteredList = await (s.QueryOver(() => p).JoinEntityAlias(() => c, () => c.Name == p.Name).ListAsync()); + + Assert.That(list, Has.Count.EqualTo(2)); + Assert.That(filteredList, Has.Count.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs index f30eed4bef8..a01c1ec2572 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2549/Fixture.cs @@ -30,7 +30,7 @@ protected override void OnTearDown() } [Test] - public void EntityJoinFilter() + public void EntityJoinFilterLinq() { using (var s = OpenSession()) { @@ -48,5 +48,23 @@ join c in s.Query() on p.Name equals c.Name Assert.That(filteredList, Has.Count.EqualTo(1)); } } + + [Test] + public void EntityJoinFilterQueryOver() + { + using (var s = OpenSession()) + { + Customer c = null; + Person p = null; + var list = s.QueryOver(() => p).JoinEntityAlias(() => c, () => c.Name == p.Name).List(); + + s.EnableFilter("DeletedCustomer").SetParameter("deleted", false); + + var filteredList = s.QueryOver(() => p).JoinEntityAlias(() => c, () => c.Name == p.Name).List(); + + Assert.That(list, Has.Count.EqualTo(2)); + Assert.That(filteredList, Has.Count.EqualTo(1)); + } + } } } From c6d9b29ba506b07eaf5a7ce99b9802872f57a652 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 18 Sep 2020 08:31:53 +1200 Subject: [PATCH 3/5] Delete EntityJoinJoinSequenceImpl --- .../Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs | 13 +++++++------ .../Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs | 15 --------------- 2 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index acb6b2b81db..82c58548e90 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -1,4 +1,6 @@ -using Antlr.Runtime; +using System; +using Antlr.Runtime; +using NHibernate.Engine; using NHibernate.Persister.Entity; using NHibernate.SqlCommand; using NHibernate.Type; @@ -15,11 +17,10 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, EntityType entityType = (EntityType) entityPersister.Type; InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias); - JoinSequence = new EntityJoinJoinSequenceImpl( - SessionFactoryHelper.Factory, - entityType, - tableAlias, - joinType); + //Note: filters don't work with entity joins + //as EntytyType.GetOnCondition always returns empty string for entity join (as IsReferenceToPrimaryKey is always true). + JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) + .AddJoin(entityType, tableAlias, joinType, Array.Empty()); fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces); } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs deleted file mode 100644 index e2bfa155dad..00000000000 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinJoinSequenceImpl.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using NHibernate.Engine; -using NHibernate.SqlCommand; -using NHibernate.Type; - -namespace NHibernate.Hql.Ast.ANTLR.Tree -{ - class EntityJoinJoinSequenceImpl : JoinSequence - { - public EntityJoinJoinSequenceImpl(ISessionFactoryImplementor factory, EntityType entityType, string tableAlias, JoinType joinType):base(factory) - { - AddJoin(entityType, tableAlias, joinType, Array.Empty()); - } - } -} From d5408fdb9900144f105d87eb8684508ea128e81b Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Thu, 17 Sep 2020 22:10:56 +0000 Subject: [PATCH 4/5] Delete obsolete comment --- src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index 82c58548e90..6098ba606ae 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -17,8 +17,6 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, EntityType entityType = (EntityType) entityPersister.Type; InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias); - //Note: filters don't work with entity joins - //as EntytyType.GetOnCondition always returns empty string for entity join (as IsReferenceToPrimaryKey is always true). JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) .AddJoin(entityType, tableAlias, joinType, Array.Empty()); From bc28e1f61dfe159384db8456dd23d1470c0d6346 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Fri, 18 Sep 2020 07:08:12 +0300 Subject: [PATCH 5/5] Add comment about EntityJoinJoinSequenceImpl --- src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs index 6098ba606ae..4458d5cecce 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs @@ -17,6 +17,7 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister, EntityType entityType = (EntityType) entityPersister.Type; InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias); + //NH Specific: hibernate uses special class EntityJoinJoinSequenceImpl JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) .AddJoin(entityType, tableAlias, joinType, Array.Empty());