Skip to content

Commit 325de61

Browse files
committed
Fix missing subclass discriminator in ON clause for entity joins (nhibernate#2600)
Fixes nhibernate#2599
1 parent f6c7e11 commit 325de61

File tree

6 files changed

+113
-16
lines changed

6 files changed

+113
-16
lines changed

src/NHibernate.Test/Async/NHSpecificTest/GH2463/Fixture.cs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
using System.Linq;
12+
using NHibernate.Criterion;
1213
using NHibernate.DomainModel;
1314
using NUnit.Framework;
1415
using NHibernate.Linq;
@@ -19,23 +20,68 @@ namespace NHibernate.Test.NHSpecificTest.GH2463
1920
[TestFixture]
2021
public class FixtureAsync : TestCase
2122
{
23+
protected override bool AppliesTo(Dialect.Dialect dialect)
24+
{
25+
return Dialect.SupportsScalarSubSelects;
26+
}
27+
2228
protected override string[] Mappings
2329
{
2430
get { return new[] {"ABC.hbm.xml"}; }
2531
}
2632

33+
protected override void OnSetUp()
34+
{
35+
using (var session = OpenSession())
36+
using (var transaction = session.BeginTransaction())
37+
{
38+
var a = new A {Name = "A", AnotherName = "X"};
39+
session.Save(a);
40+
41+
var b = new B {Name = "B", AnotherName = "X"};
42+
session.Save(b);
43+
44+
transaction.Commit();
45+
}
46+
}
47+
48+
protected override void OnTearDown()
49+
{
50+
using (var session = OpenSession())
51+
using (var transaction = session.BeginTransaction())
52+
{
53+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
54+
55+
transaction.Commit();
56+
}
57+
}
58+
59+
//Also see GH-2599
2760
[Test]
28-
public async Task CanJoinOnEntityWithDiscriminatorAsync()
61+
public async Task CanJoinOnEntityWithDiscriminatorLinqAsync()
2962
{
3063
using (var s = OpenSession())
3164
{
32-
await (s.Query<A>().Join(
33-
s.Query<A>(),
34-
a => a.Id,
35-
b => b.Id,
65+
var list = await (s.Query<A>().Join(
66+
s.Query<B>(),
67+
a => a.AnotherName,
68+
b => b.AnotherName,
3669
(a, b) =>
3770
new {a, b}).ToListAsync());
3871
}
3972
}
73+
74+
[Test]
75+
public async Task CanJoinOnEntityWithDiscriminatorQueryOverAsync()
76+
{
77+
using (var s = OpenSession())
78+
{
79+
A a = null;
80+
B b = null;
81+
var list = await (s.QueryOver<A>(() => a)
82+
.JoinEntityAlias(() => b, () => a.AnotherName == b.AnotherName)
83+
.Select((x) => a.AsEntity(), (x) => b.AsEntity()).ListAsync<object[]>());
84+
}
85+
}
4086
}
4187
}
Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq;
2+
using NHibernate.Criterion;
23
using NHibernate.DomainModel;
34
using NUnit.Framework;
45

@@ -7,23 +8,68 @@ namespace NHibernate.Test.NHSpecificTest.GH2463
78
[TestFixture]
89
public class Fixture : TestCase
910
{
11+
protected override bool AppliesTo(Dialect.Dialect dialect)
12+
{
13+
return Dialect.SupportsScalarSubSelects;
14+
}
15+
1016
protected override string[] Mappings
1117
{
1218
get { return new[] {"ABC.hbm.xml"}; }
1319
}
1420

21+
protected override void OnSetUp()
22+
{
23+
using (var session = OpenSession())
24+
using (var transaction = session.BeginTransaction())
25+
{
26+
var a = new A {Name = "A", AnotherName = "X"};
27+
session.Save(a);
28+
29+
var b = new B {Name = "B", AnotherName = "X"};
30+
session.Save(b);
31+
32+
transaction.Commit();
33+
}
34+
}
35+
36+
protected override void OnTearDown()
37+
{
38+
using (var session = OpenSession())
39+
using (var transaction = session.BeginTransaction())
40+
{
41+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
42+
43+
transaction.Commit();
44+
}
45+
}
46+
47+
//Also see GH-2599
1548
[Test]
16-
public void CanJoinOnEntityWithDiscriminator()
49+
public void CanJoinOnEntityWithDiscriminatorLinq()
1750
{
1851
using (var s = OpenSession())
1952
{
20-
s.Query<A>().Join(
21-
s.Query<A>(),
22-
a => a.Id,
23-
b => b.Id,
53+
var list = s.Query<A>().Join(
54+
s.Query<B>(),
55+
a => a.AnotherName,
56+
b => b.AnotherName,
2457
(a, b) =>
2558
new {a, b}).ToList();
2659
}
2760
}
61+
62+
[Test]
63+
public void CanJoinOnEntityWithDiscriminatorQueryOver()
64+
{
65+
using (var s = OpenSession())
66+
{
67+
A a = null;
68+
B b = null;
69+
var list = s.QueryOver<A>(() => a)
70+
.JoinEntityAlias(() => b, () => a.AnotherName == b.AnotherName)
71+
.Select((x) => a.AsEntity(), (x) => b.AsEntity()).List<object[]>();
72+
}
73+
}
2874
}
2975
}

src/NHibernate/Engine/JoinSequence.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,9 @@ internal virtual JoinFragment ToJoinFragment(
193193
else
194194
{
195195
// NH Different behavior : NH1179 and NH1293
196-
// Apply filters in Many-To-One association
196+
// Apply filters for entity joins and Many-To-One association
197197
var enabledForManyToOne = FilterHelper.GetEnabledForManyToOne(enabledFilters);
198-
condition = new SqlString(string.IsNullOrEmpty(on) && enabledForManyToOne.Count > 0
198+
condition = new SqlString(string.IsNullOrEmpty(on) && (ForceFilter || enabledForManyToOne.Count > 0)
199199
? join.Joinable.FilterFragment(join.Alias, enabledForManyToOne)
200200
: on);
201201
}
@@ -327,5 +327,7 @@ public interface ISelector
327327
internal string RootAlias => rootAlias;
328328

329329
public ISessionFactoryImplementor Factory => factory;
330+
331+
internal bool ForceFilter { get; set; }
330332
}
331333
}

src/NHibernate/Hql/Ast/ANTLR/Tree/EntityJoinFromElement.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public EntityJoinFromElement(FromClause fromClause, IQueryable entityPersister,
1818
InitializeEntity(fromClause, entityPersister.EntityName, entityPersister, entityType, alias, tableAlias);
1919

2020
//NH Specific: hibernate uses special class EntityJoinJoinSequenceImpl
21-
JoinSequence = new JoinSequence(SessionFactoryHelper.Factory)
21+
JoinSequence = new JoinSequence(SessionFactoryHelper.Factory) {ForceFilter = true}
2222
.AddJoin(entityType, tableAlias, joinType, Array.Empty<string>());
2323

2424
fromClause.Walker.AddQuerySpaces(entityPersister.QuerySpaces);

src/NHibernate/Loader/JoinWalker.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ internal void AddExplicitEntityJoinAssociation(
388388
GetWithClause(path, pathAlias),
389389
Factory,
390390
enabledFilters,
391-
GetSelectMode(path)), path);
391+
GetSelectMode(path)) {ForceFilter = true},
392+
path);
392393
AddAssociation(assoc);
393394
}
394395

@@ -851,8 +852,8 @@ protected JoinFragment MergeOuterJoins(IList<OuterJoinableAssociation> associati
851852
{
852853
oj.AddJoins(outerjoin);
853854
// NH Different behavior : NH1179 and NH1293
854-
// Apply filters in Many-To-One association
855-
if (enabledFiltersForManyToOne.Count > 0)
855+
// Apply filters for entity joins and Many-To-One associations
856+
if (oj.ForceFilter || enabledFiltersForManyToOne.Count > 0)
856857
{
857858
string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne);
858859
bool joinClauseDoesNotContainsFilterAlready =

src/NHibernate/Loader/OuterJoinableAssociation.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public SelectMode SelectMode
100100

101101
public ISet<string> EntityFetchLazyProperties { get; set; }
102102

103+
internal bool ForceFilter { get; set; }
104+
103105
public int GetOwner(IList<OuterJoinableAssociation> associations)
104106
{
105107
if (IsEntityType || IsCollection)

0 commit comments

Comments
 (0)