Skip to content

Fix discriminator in where clause on outer joins #471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ AssemblyInfo.cs
hibernate.cfg.xml
available-test-configurations
current-test-configuration
NHibernate.VisualState.xml
NHibernate.VisualState.xml
.vs/
40 changes: 22 additions & 18 deletions src/NHibernate.Everything.sln
Original file line number Diff line number Diff line change
@@ -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}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
59 changes: 59 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3506/DiscriminatorFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Linq;
using NHibernate.Linq;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH3506
{
[TestFixture]
public class DiscriminatorFixture : 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 JoinedDiscriminatorIsNotInWhere()
{
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<Person>()
.JoinQueryOver(p => p.Employer, SqlCommand.JoinType.LeftOuterJoin);

Assert.AreEqual(2, result.List().Count);
}
}
}
}
21 changes: 21 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3506/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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
{
}
}
23 changes: 23 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3506/Mappings.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.NH3506">

<class name="Entity">
<id name="Id" generator="guid.comb" />
<discriminator column="ObjectType"/>

<property name="Name" />
<property name="Deleted" />

<subclass name="Person" discriminator-value="Person">
<many-to-one name="Employer" column="EmployerId" />
</subclass>

<subclass name="Employer" discriminator-value="Employer">
</subclass>

<filter name="deletedFilter" />
</class>

<filter-def name="deletedFilter" condition="Deleted is null"></filter-def>

</hibernate-mapping>
3 changes: 3 additions & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,8 @@
<Compile Include="NHSpecificTest\BagWithLazyExtraAndFilter\Domain.cs" />
<Compile Include="NHSpecificTest\BagWithLazyExtraAndFilter\Fixture.cs" />
<Compile Include="Component\Basic\ComponentWithUniqueConstraintTests.cs" />
<Compile Include="NHSpecificTest\NH3506\Entity.cs" />
<Compile Include="NHSpecificTest\NH3506\DiscriminatorFixture.cs" />
<Compile Include="NHSpecificTest\NH3401\Entity.cs" />
<Compile Include="NHSpecificTest\NH3401\Fixture.cs" />
<Compile Include="NHSpecificTest\NH1863\Domain.cs" />
Expand Down Expand Up @@ -2930,6 +2932,7 @@
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="NHSpecificTest\NH3506\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3401\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2049\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1863\Mappings.hbm.xml" />
Expand Down
4 changes: 2 additions & 2 deletions src/NHibernate/Engine/JoinSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Hql/Ast/ANTLR/Util/SyntheticAndFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private IASTNode Create(int tokenType, string text)

public virtual void AddDiscriminatorWhereFragment(IRestrictableStatement statement, IQueryable persister, IDictionary<string, IFilter> enabledFilters, string alias)
{
string whereFragment = persister.FilterFragment(alias, enabledFilters).Trim();
string whereFragment = persister.FilterFragment(alias, enabledFilters, false).Trim();
if (string.Empty.Equals(whereFragment))
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Loader/Collection/OneToManyJoinWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Loader/Criteria/CriteriaJoinWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public string[] UserAliases
/// </summary>
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<string> QuerySpaces
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Loader/Entity/CascadeEntityJoinWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, IFilter>()));
.Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>(), false));

InitAll(whereCondition.ToSqlString(), SqlString.Empty, LockMode.Read);
}
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Loader/Entity/EntityJoinWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, IFilter>()));
.Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>(), false));

InitAll(whereCondition.ToSqlString(), SqlString.Empty, lockMode);
}
Expand Down
8 changes: 5 additions & 3 deletions src/NHibernate/Loader/JoinWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -647,17 +647,19 @@ protected JoinFragment MergeOuterJoins(IList<OuterJoinableAssociation> 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)
{
outerjoin.AddCondition(manyToOneFilterFragment);
}
outerjoin.AddCondition(manyToOneFilterFragment);
}
}
}
last = oj;
Expand Down
1 change: 1 addition & 0 deletions src/NHibernate/Loader/OuterJoinableAssociation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -1402,12 +1402,15 @@ protected virtual string FilterFragment(string alias)
return HasWhere ? " and " + GetSQLWhereString(alias) : "";
}

public virtual string FilterFragment(string alias, IDictionary<string, IFilter> enabledFilters)
public virtual string FilterFragment(string alias, IDictionary<string, IFilter> 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)
Expand Down
7 changes: 5 additions & 2 deletions src/NHibernate/Persister/Entity/AbstractEntityPersister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3198,12 +3198,15 @@ protected void LogStaticSQL()
}
}

public virtual string FilterFragment(string alias, IDictionary<string, IFilter> enabledFilters)
public virtual string FilterFragment(string alias, IDictionary<string, IFilter> 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)
Expand Down
2 changes: 1 addition & 1 deletion src/NHibernate/Persister/Entity/IJoinable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string cu
/// <summary>
/// Get the where clause filter, given a query alias and considering enabled session filters
/// </summary>
string FilterFragment(string alias, IDictionary<string, IFilter> enabledFilters);
string FilterFragment(string alias, IDictionary<string, IFilter> enabledFilters, bool excludeDiscriminator);

string OneToManyFilterFragment(string alias);

Expand Down
12 changes: 6 additions & 6 deletions src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public class SingleTableEntityPersister : AbstractEntityPersister, IQueryable

private static readonly object NullDiscriminator = new object();
private static readonly object NotNullDiscriminator = new object();

public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
ISessionFactoryImplementor factory, IMapping mapping)
: base(persistentClass, cache, factory)
{
Expand Down Expand Up @@ -496,8 +496,8 @@ protected override bool IsSubclassTableSequentialSelect(int table)
{
return subclassTableSequentialSelect[table] && !isClassOrSuperclassTable[table];
}

public override string FromTableFragment(string name)
public override string FromTableFragment(string name)
{
return TableName + ' ' + name;
}
Expand All @@ -510,8 +510,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;
}
Expand Down
Loading