From 124cdfb42ec6ccbe9a28651d4b50035a1b267c53 Mon Sep 17 00:00:00 2001 From: ithielnor Date: Thu, 14 Apr 2016 14:18:56 -0400 Subject: [PATCH 1/4] Fix descriminators on outer joins --- .gitignore | 3 ++- src/NHibernate/Loader/JoinWalker.cs | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e8cd4be0f5c..82c5a4d87a0 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ AssemblyInfo.cs hibernate.cfg.xml available-test-configurations current-test-configuration -NHibernate.VisualState.xml \ No newline at end of file +NHibernate.VisualState.xml +.vs/ \ No newline at end of file diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index 676a30aec07..01ee46a48d2 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -656,8 +656,10 @@ protected JoinFragment MergeOuterJoins(IList associati outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { - outerjoin.AddCondition(manyToOneFilterFragment); - } + // Ensure that the join condition is added to the join, not the where clause. + // Adding the condition to the where clause causes left joins to become inner joins. + outerjoin.AddFromFragmentString(new SqlString(manyToOneFilterFragment)); + } } } last = oj; From f3e5430e5d1df1b8c6d1c33fc8647ae01ab11541 Mon Sep 17 00:00:00 2001 From: ithielnor Date: Fri, 15 Apr 2016 09:34:25 -0400 Subject: [PATCH 2/4] Add test for NH3506 --- .../NH3506/DescriminatorFixture.cs | 59 +++++++++++++++++++ .../NHSpecificTest/NH3506/Entity.cs | 22 +++++++ .../NHSpecificTest/NH3506/Mappings.hbm.xml | 23 ++++++++ src/NHibernate.Test/NHibernate.Test.csproj | 3 + src/NHibernate/Loader/JoinWalker.cs | 4 +- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3506/Mappings.hbm.xml diff --git a/src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs new file mode 100644 index 00000000000..01b574eb156 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs @@ -0,0 +1,59 @@ +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3506 +{ + [TestFixture] + public class DescriminatorFixture : BugTestCase + { + protected override void OnSetUp() + { + using (ISession session = OpenSession()) + using (ITransaction transaction = session.BeginTransaction()) + { + var e1 = new Person {Name = "Bob"}; + session.Save(e1); + + var e2 = new Person { Name = "Sally" }; + session.Save(e2); + + var e3 = new Employer { Name = "Company ABC" }; + session.Save(e3); + + e1.Employer = e3; + + session.Flush(); + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (ISession session = OpenSession()) + using (ITransaction transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + + [Test] + public void DescriminatorFilterIsInFromFragment() + { + using (ISession session = OpenSession()) + using (session.BeginTransaction()) + { + // bug only occurs when a filter is enabled with use-many-to-one=true + session.EnableFilter("deletedFilter"); + + var result = session.QueryOver() + .JoinQueryOver(p => p.Employer, SqlCommand.JoinType.LeftOuterJoin); + + Assert.AreEqual(2, result.List().Count); + } + } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs new file mode 100644 index 00000000000..a11e055b013 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs @@ -0,0 +1,22 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.NH3506 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + + public virtual DateTime? Deleted { get; set; } + } + + class Person : Entity + { + public virtual Employer Employer { get; set; } + } + + class Employer : Entity + { + + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3506/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH3506/Mappings.hbm.xml new file mode 100644 index 00000000000..daa46a03d63 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3506/Mappings.hbm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index ed517b32aa0..eae41ece326 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -675,6 +675,8 @@ + + @@ -2930,6 +2932,7 @@ + diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index 01ee46a48d2..da4b953f2fc 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -656,9 +656,7 @@ protected JoinFragment MergeOuterJoins(IList associati outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { - // Ensure that the join condition is added to the join, not the where clause. - // Adding the condition to the where clause causes left joins to become inner joins. - outerjoin.AddFromFragmentString(new SqlString(manyToOneFilterFragment)); + outerjoin.AddCondition(manyToOneFilterFragment); } } } From dbd3156e667aa3a1902682b116169c05947ff965 Mon Sep 17 00:00:00 2001 From: ithielnor Date: Fri, 15 Apr 2016 10:50:04 -0400 Subject: [PATCH 3/4] Split paths in FilterFragment based on arg --- src/NHibernate.Everything.sln | 40 ++++++++++--------- ...atorFixture.cs => DiscriminatorFixture.cs} | 8 ++-- .../NHSpecificTest/NH3506/Entity.cs | 1 - src/NHibernate/Engine/JoinSequence.cs | 4 +- .../Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs | 2 +- .../Collection/BasicCollectionJoinWalker.cs | 2 +- .../Loader/Collection/OneToManyJoinWalker.cs | 2 +- .../Loader/Criteria/CriteriaJoinWalker.cs | 2 +- .../Loader/Entity/CascadeEntityJoinWalker.cs | 2 +- .../Loader/Entity/EntityJoinWalker.cs | 2 +- src/NHibernate/Loader/JoinWalker.cs | 4 +- .../Loader/OuterJoinableAssociation.cs | 1 + .../Collection/AbstractCollectionPersister.cs | 9 +++-- .../Entity/AbstractEntityPersister.cs | 7 +++- src/NHibernate/Persister/Entity/IJoinable.cs | 2 +- .../Entity/SingleTableEntityPersister.cs | 23 ++++++++--- src/NHibernate/Type/CollectionType.cs | 2 +- src/NHibernate/Type/EntityType.cs | 2 +- 18 files changed, 69 insertions(+), 46 deletions(-) rename src/NHibernate.Test/NHSpecificTest/NH3506/{DescriminatorFixture.cs => DiscriminatorFixture.cs} (88%) diff --git a/src/NHibernate.Everything.sln b/src/NHibernate.Everything.sln index e7c6a288fc2..a0f800e6983 100644 --- a/src/NHibernate.Everything.sln +++ b/src/NHibernate.Everything.sln @@ -1,6 +1,8 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Support", "Support", "{9BDB5C84-14EC-4384-B423-9E319675B3CA}" ProjectSection(FolderStartupServices) = postProject {B4F97281-0DBD-4835-9ED8-7DFB966E87FF} = {B4F97281-0DBD-4835-9ED8-7DFB966E87FF} @@ -91,6 +93,7 @@ Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "NHibernate.Example.Web", "N Release.AspNetCompiler.FixedNames = "false" Release.AspNetCompiler.Debug = "False" VWDPort = "3041" + SlnRelativePath = "NHibernate.Example.Web\" DefaultWebSiteLanguage = "Visual C#" EndProjectSection EndProject @@ -158,17 +161,18 @@ Global {58CE4584-31B9-4E74-A7FB-5D40BFAD0876}.Release|Any CPU.Build.0 = Release|Any CPU {58CE4584-31B9-4E74-A7FB-5D40BFAD0876}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU {58CE4584-31B9-4E74-A7FB-5D40BFAD0876}.Release|Mixed Platforms.Build.0 = Debug|Any CPU - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|.NET.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|.NET.Build.0 = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Any CPU.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Any CPU.Build.0 = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Mixed Platforms.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Mixed Platforms.Build.0 = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|.NET.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|.NET.Build.0 = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Any CPU.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Mixed Platforms.ActiveCfg = Debug|.NET - {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Mixed Platforms.Build.0 = Debug|.NET + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|.NET.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|.NET.Build.0 = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|.NET.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|.NET.Build.0 = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Any CPU.Build.0 = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C5D6EE68-1760-4F97-AD31-42343593D8C1}.Release|Mixed Platforms.Build.0 = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|.NET.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -193,19 +197,19 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {C91E7018-3C67-4830-963A-C388C75E1BD5} = {28EA2C84-8295-49ED-BC67-803B7778513E} + {094F74CD-2DD7-496F-BC48-A6D357BF33FD} = {28EA2C84-8295-49ED-BC67-803B7778513E} + {92509065-DAEA-4457-8300-C7B64CD0E9F4} = {28EA2C84-8295-49ED-BC67-803B7778513E} {4CE16C2F-EFF6-48A4-99BC-8984DCC143FA} = {9BDB5C84-14EC-4384-B423-9E319675B3CA} {1631B0BA-59AC-4F0D-B300-3F64CC7579C9} = {9BDB5C84-14EC-4384-B423-9E319675B3CA} {936E50BD-4027-4864-ADE9-423C3FBF7FFB} = {9BDB5C84-14EC-4384-B423-9E319675B3CA} - {094F74CD-2DD7-496F-BC48-A6D357BF33FD} = {28EA2C84-8295-49ED-BC67-803B7778513E} - {92509065-DAEA-4457-8300-C7B64CD0E9F4} = {28EA2C84-8295-49ED-BC67-803B7778513E} - {C91E7018-3C67-4830-963A-C388C75E1BD5} = {28EA2C84-8295-49ED-BC67-803B7778513E} {5909BFE7-93CF-4E5F-BE22-6293368AF01D} = {094F74CD-2DD7-496F-BC48-A6D357BF33FD} {5C649B55-1B3F-4C38-9998-1B043E94A244} = {094F74CD-2DD7-496F-BC48-A6D357BF33FD} {7AEE5B37-C552-4E59-9B6F-88755BCB5070} = {094F74CD-2DD7-496F-BC48-A6D357BF33FD} - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C} = {094F74CD-2DD7-496F-BC48-A6D357BF33FD} - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D} = {92509065-DAEA-4457-8300-C7B64CD0E9F4} {4C251E3E-6EA1-4A51-BBCB-F9C42AE55344} = {C91E7018-3C67-4830-963A-C388C75E1BD5} {58CE4584-31B9-4E74-A7FB-5D40BFAD0876} = {C91E7018-3C67-4830-963A-C388C75E1BD5} + {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D} = {92509065-DAEA-4457-8300-C7B64CD0E9F4} + {7C2EF610-BCA0-4D1F-898A-DE9908E4970C} = {094F74CD-2DD7-496F-BC48-A6D357BF33FD} EndGlobalSection GlobalSection(TextTemplating) = postSolution TextTemplating = 1 diff --git a/src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3506/DiscriminatorFixture.cs similarity index 88% rename from src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs rename to src/NHibernate.Test/NHSpecificTest/NH3506/DiscriminatorFixture.cs index 01b574eb156..d6c2eca54e3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3506/DescriminatorFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3506/DiscriminatorFixture.cs @@ -5,7 +5,7 @@ namespace NHibernate.Test.NHSpecificTest.NH3506 { [TestFixture] - public class DescriminatorFixture : BugTestCase + public class DiscriminatorFixture : BugTestCase { protected override void OnSetUp() { @@ -41,7 +41,7 @@ protected override void OnTearDown() } [Test] - public void DescriminatorFilterIsInFromFragment() + public void JoinedDiscriminatorIsNotInWhere() { using (ISession session = OpenSession()) using (session.BeginTransaction()) @@ -54,6 +54,6 @@ public void DescriminatorFilterIsInFromFragment() Assert.AreEqual(2, result.List().Count); } - } - } + } + } } \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs index a11e055b013..d7016171b62 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs @@ -17,6 +17,5 @@ class Person : Entity class Employer : Entity { - } } \ No newline at end of file diff --git a/src/NHibernate/Engine/JoinSequence.cs b/src/NHibernate/Engine/JoinSequence.cs index 79a274a616b..8521cbad0c9 100644 --- a/src/NHibernate/Engine/JoinSequence.cs +++ b/src/NHibernate/Engine/JoinSequence.cs @@ -146,7 +146,7 @@ public JoinFragment ToJoinFragment( if (rootJoinable != null) { joinFragment.AddCrossJoin(rootJoinable.TableName, rootAlias); - string filterCondition = rootJoinable.FilterFragment(rootAlias, enabledFilters); + string filterCondition = rootJoinable.FilterFragment(rootAlias, enabledFilters, false); // JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it // can put the where clause fragment in the right place in the SQL AST. 'hasFilterCondition' keeps track // of that fact. @@ -186,7 +186,7 @@ public JoinFragment ToJoinFragment( // Apply filters in Many-To-One association var enabledForManyToOne = FilterHelper.GetEnabledForManyToOne(enabledFilters); condition = new SqlString(string.IsNullOrEmpty(on) && enabledForManyToOne.Count > 0 - ? join.Joinable.FilterFragment(join.Alias, enabledForManyToOne) + ? join.Joinable.FilterFragment(join.Alias, enabledForManyToOne, true) : on); } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs index 857db9652ec..06fc32ccba7 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs @@ -147,7 +147,7 @@ private IASTNode Create(int tokenType, string text) public virtual void AddDiscriminatorWhereFragment(IRestrictableStatement statement, IQueryable persister, IDictionary enabledFilters, string alias) { - string whereFragment = persister.FilterFragment(alias, enabledFilters).Trim(); + string whereFragment = persister.FilterFragment(alias, enabledFilters, false).Trim(); if (string.Empty.Equals(whereFragment)) { return; diff --git a/src/NHibernate/Loader/Collection/BasicCollectionJoinWalker.cs b/src/NHibernate/Loader/Collection/BasicCollectionJoinWalker.cs index e84379351cf..f63acf20b09 100644 --- a/src/NHibernate/Loader/Collection/BasicCollectionJoinWalker.cs +++ b/src/NHibernate/Loader/Collection/BasicCollectionJoinWalker.cs @@ -46,7 +46,7 @@ private void InitStatementString(string alias, int batchSize, SqlString subquery SqlStringBuilder whereString = WhereString(alias, collectionPersister.KeyColumnNames, subquery, batchSize); string manyToManyOrderBy = string.Empty; - string filter = collectionPersister.FilterFragment(alias, EnabledFilters); + string filter = collectionPersister.FilterFragment(alias, EnabledFilters, false); if (collectionPersister.IsManyToMany) { diff --git a/src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs b/src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs index 5cf101437c1..39c845edfca 100644 --- a/src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs +++ b/src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs @@ -58,7 +58,7 @@ private void InitStatementString(IOuterJoinLoadable elementPersister, string ali CollectionSuffixes = BasicLoader.GenerateSuffixes(joins + 1, collectionJoins); SqlStringBuilder whereString = WhereString(alias, oneToManyPersister.KeyColumnNames, subquery, batchSize); - string filter = oneToManyPersister.FilterFragment(alias, EnabledFilters); + string filter = oneToManyPersister.FilterFragment(alias, EnabledFilters, false); whereString.Insert(0, StringHelper.MoveAndToBeginning(filter)); JoinFragment ojf = MergeOuterJoins(associations); diff --git a/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs b/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs index 72edbe9a6c5..8256445e8ab 100644 --- a/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs +++ b/src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs @@ -96,7 +96,7 @@ public string[] UserAliases /// protected override SqlString WhereFragment { - get { return base.WhereFragment.Append(((IQueryable) Persister).FilterFragment(Alias, EnabledFilters)); } + get { return base.WhereFragment.Append(((IQueryable) Persister).FilterFragment(Alias, EnabledFilters, false)); } } public ISet QuerySpaces diff --git a/src/NHibernate/Loader/Entity/CascadeEntityJoinWalker.cs b/src/NHibernate/Loader/Entity/CascadeEntityJoinWalker.cs index 1407832d5ba..c3df438f4cd 100644 --- a/src/NHibernate/Loader/Entity/CascadeEntityJoinWalker.cs +++ b/src/NHibernate/Loader/Entity/CascadeEntityJoinWalker.cs @@ -17,7 +17,7 @@ public CascadeEntityJoinWalker(IOuterJoinLoadable persister, CascadingAction act cascadeAction = action; SqlStringBuilder whereCondition = WhereString(Alias, persister.IdentifierColumnNames, 1) //include the discriminator and class-level where, but not filters - .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass())); + .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass(), false)); InitAll(whereCondition.ToSqlString(), SqlString.Empty, LockMode.Read); } diff --git a/src/NHibernate/Loader/Entity/EntityJoinWalker.cs b/src/NHibernate/Loader/Entity/EntityJoinWalker.cs index 55bc52327c6..5b7f4e90967 100644 --- a/src/NHibernate/Loader/Entity/EntityJoinWalker.cs +++ b/src/NHibernate/Loader/Entity/EntityJoinWalker.cs @@ -23,7 +23,7 @@ public EntityJoinWalker(IOuterJoinLoadable persister, string[] uniqueKey, int ba SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize) //include the discriminator and class-level where, but not filters - .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass())); + .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass(), false)); InitAll(whereCondition.ToSqlString(), SqlString.Empty, lockMode); } diff --git a/src/NHibernate/Loader/JoinWalker.cs b/src/NHibernate/Loader/JoinWalker.cs index da4b953f2fc..a5f94aae0d5 100644 --- a/src/NHibernate/Loader/JoinWalker.cs +++ b/src/NHibernate/Loader/JoinWalker.cs @@ -647,11 +647,13 @@ protected JoinFragment MergeOuterJoins(IList associati else { oj.AddJoins(outerjoin); + // NH Different behavior : NH1179 and NH1293 // Apply filters in Many-To-One association if (enabledFiltersForManyToOne.Count > 0) { - string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne); + // never include descriminator here + string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne, true); bool joinClauseDoesNotContainsFilterAlready = outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) diff --git a/src/NHibernate/Loader/OuterJoinableAssociation.cs b/src/NHibernate/Loader/OuterJoinableAssociation.cs index a9409b978c4..d57bbcbf220 100644 --- a/src/NHibernate/Loader/OuterJoinableAssociation.cs +++ b/src/NHibernate/Loader/OuterJoinableAssociation.cs @@ -35,6 +35,7 @@ public OuterJoinableAssociation(IAssociationType joinableType, String lhsAlias, on = new SqlString(joinableType.GetOnCondition(rhsAlias, factory, enabledFilters)); if (StringHelper.IsNotEmpty(withClause)) on = on.Append(" and ( ").Append(withClause).Append(" )"); + this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application } diff --git a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs index 99ebc8ae7bc..82109371912 100644 --- a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs @@ -852,7 +852,7 @@ private SqlString GenerateSelectSizeString(ISessionImplementor sessionImplemento .AddWhereFragment(KeyColumnNames, KeyType, "=") .AddColumn(selectValue) .ToSqlString() - .Append(FilterFragment(TableName, sessionImplementor.EnabledFilters)); + .Append(FilterFragment(TableName, sessionImplementor.EnabledFilters, false)); } protected virtual string GetCountSqlSelectClause() @@ -1402,12 +1402,15 @@ protected virtual string FilterFragment(string alias) return HasWhere ? " and " + GetSQLWhereString(alias) : ""; } - public virtual string FilterFragment(string alias, IDictionary enabledFilters) + public virtual string FilterFragment(string alias, IDictionary enabledFilters, bool excludeDescriminator) { StringBuilder sessionFilterFragment = new StringBuilder(); filterHelper.Render(sessionFilterFragment, alias, enabledFilters); - return sessionFilterFragment.Append(FilterFragment(alias)).ToString(); + if (excludeDescriminator) + return sessionFilterFragment.ToString(); + else + return sessionFilterFragment.Append(FilterFragment(alias)).ToString(); } public string OneToManyFilterFragment(string alias) diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index e7dc9c6ca74..60f50ae0f40 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -3198,12 +3198,15 @@ protected void LogStaticSQL() } } - public virtual string FilterFragment(string alias, IDictionary enabledFilters) + public virtual string FilterFragment(string alias, IDictionary enabledFilters, bool outerJoin) { StringBuilder sessionFilterFragment = new StringBuilder(); filterHelper.Render(sessionFilterFragment, GenerateFilterConditionAlias(alias), enabledFilters); - return sessionFilterFragment.Append(FilterFragment(alias)).ToString(); + if (outerJoin) + return sessionFilterFragment.ToString(); + else + return sessionFilterFragment.Append(FilterFragment(alias)).ToString(); } public virtual string GenerateFilterConditionAlias(string rootAlias) diff --git a/src/NHibernate/Persister/Entity/IJoinable.cs b/src/NHibernate/Persister/Entity/IJoinable.cs index cad58776fb7..4dff98bf32f 100644 --- a/src/NHibernate/Persister/Entity/IJoinable.cs +++ b/src/NHibernate/Persister/Entity/IJoinable.cs @@ -57,7 +57,7 @@ string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string cu /// /// Get the where clause filter, given a query alias and considering enabled session filters /// - string FilterFragment(string alias, IDictionary enabledFilters); + string FilterFragment(string alias, IDictionary enabledFilters, bool excludeDiscriminator); string OneToManyFilterFragment(string alias); diff --git a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs index 32d3a86b77a..cb489bd972d 100644 --- a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs @@ -66,9 +66,15 @@ public class SingleTableEntityPersister : AbstractEntityPersister, IQueryable private readonly Dictionary sequentialSelectStringsByEntityName = new Dictionary(); private static readonly object NullDiscriminator = new object(); - private static readonly object NotNullDiscriminator = new object(); - - public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, + private static readonly object NotNullDiscriminator = new object(); + + #region Dynamic filters attached to the class-level + + private readonly FilterHelper filterHelper; + + #endregion + + public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping mapping) : base(persistentClass, cache, factory) { @@ -497,7 +503,12 @@ protected override bool IsSubclassTableSequentialSelect(int table) return subclassTableSequentialSelect[table] && !isClassOrSuperclassTable[table]; } - public override string FromTableFragment(string name) + public override SqlString FromJoinFragment(string alias, bool innerJoin, bool includeSubclasses) + { + return base.FromJoinFragment(alias, innerJoin, includeSubclasses); + } + + public override string FromTableFragment(string name) { return TableName + ' ' + name; } @@ -510,8 +521,8 @@ public override string FilterFragment(string alias) return result; } - - public override string OneToManyFilterFragment(string alias) + + public override string OneToManyFilterFragment(string alias) { return forceDiscriminator ? DiscriminatorFilterFragment(alias) : string.Empty; } diff --git a/src/NHibernate/Type/CollectionType.cs b/src/NHibernate/Type/CollectionType.cs index 3b301066433..82fd967cfb5 100644 --- a/src/NHibernate/Type/CollectionType.cs +++ b/src/NHibernate/Type/CollectionType.cs @@ -550,7 +550,7 @@ public virtual object GetIdOfOwnerOrNull(object key, ISessionImplementor session public string GetOnCondition(string alias, ISessionFactoryImplementor factory, IDictionary enabledFilters) { - return GetAssociatedJoinable(factory).FilterFragment(alias, enabledFilters); + return GetAssociatedJoinable(factory).FilterFragment(alias, enabledFilters, false); } public override object FromXMLNode(XmlNode xml, IMapping factory) diff --git a/src/NHibernate/Type/EntityType.cs b/src/NHibernate/Type/EntityType.cs index 8cf6ea2170c..2233d15c5d2 100644 --- a/src/NHibernate/Type/EntityType.cs +++ b/src/NHibernate/Type/EntityType.cs @@ -526,7 +526,7 @@ public string GetOnCondition(string alias, ISessionFactoryImplementor factory, I } else { - return GetAssociatedJoinable(factory).FilterFragment(alias, enabledFilters); + return GetAssociatedJoinable(factory).FilterFragment(alias, enabledFilters, false); } } From ef943a74221274c33c889e1291d2e81d1a5264c0 Mon Sep 17 00:00:00 2001 From: ithielnor Date: Fri, 15 Apr 2016 10:56:42 -0400 Subject: [PATCH 4/4] A little more cleanup on SingleTableEntityPersister --- src/NHibernate.Test/NHibernate.Test.csproj | 2 +- .../Entity/SingleTableEntityPersister.cs | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index eae41ece326..dc2f7dcb7a5 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -676,7 +676,7 @@ - + diff --git a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs index cb489bd972d..2cc0d30635f 100644 --- a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs @@ -66,13 +66,7 @@ public class SingleTableEntityPersister : AbstractEntityPersister, IQueryable private readonly Dictionary sequentialSelectStringsByEntityName = new Dictionary(); private static readonly object NullDiscriminator = new object(); - private static readonly object NotNullDiscriminator = new object(); - - #region Dynamic filters attached to the class-level - - private readonly FilterHelper filterHelper; - - #endregion + private static readonly object NotNullDiscriminator = new object(); public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping mapping) @@ -502,12 +496,7 @@ protected override bool IsSubclassTableSequentialSelect(int table) { return subclassTableSequentialSelect[table] && !isClassOrSuperclassTable[table]; } - - public override SqlString FromJoinFragment(string alias, bool innerJoin, bool includeSubclasses) - { - return base.FromJoinFragment(alias, innerJoin, includeSubclasses); - } - + public override string FromTableFragment(string name) { return TableName + ' ' + name;