Skip to content

Commit 160e35d

Browse files
authored
Fix collection filter on subclass columns (#3264)
Closes #3079
1 parent 26b557f commit 160e35d

File tree

4 files changed

+54
-83
lines changed

4 files changed

+54
-83
lines changed

src/NHibernate.Test/Async/SubclassFilterTest/JoinedSubclassFilterTest.cs

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
//------------------------------------------------------------------------------
99

1010

11-
using System;
1211
using System.Collections;
1312
using NUnit.Framework;
1413
using System.Linq;
@@ -17,29 +16,36 @@
1716
namespace NHibernate.Test.SubclassFilterTest
1817
{
1918
using System.Threading.Tasks;
20-
using System.Threading;
2119
[TestFixture]
2220
public class JoinedSubclassFilterTestAsync : TestCase
2321
{
24-
protected override string[] Mappings
22+
protected override string[] Mappings => new[] {"SubclassFilterTest.joined-subclass.hbm.xml"};
23+
24+
protected override string MappingsAssembly => "NHibernate.Test";
25+
26+
protected override void OnSetUp()
2527
{
26-
get { return new string[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; }
28+
using var s = OpenSession();
29+
using var t = s.BeginTransaction();
30+
PrepareTestData(s);
31+
t.Commit();
2732
}
2833

29-
protected override string MappingsAssembly
34+
protected override void OnTearDown()
3035
{
31-
get { return "NHibernate.Test"; }
36+
using var s = OpenSession();
37+
using var t = s.BeginTransaction();
38+
s.Delete("from Customer c where c.ContactOwner is not null");
39+
s.Delete("from Employee e where e.Manager is not null");
40+
s.Delete("from Person");
41+
t.Commit();
3242
}
3343

3444
[Test]
3545
public async Task FiltersWithSubclassAsync()
3646
{
37-
ISession s = OpenSession();
47+
using var s = OpenSession();
3848
s.EnableFilter("region").SetParameter("userRegion", "US");
39-
ITransaction t = s.BeginTransaction();
40-
41-
await (PrepareTestDataAsync(s));
42-
s.Clear();
4349

4450
IList results;
4551

@@ -62,14 +68,6 @@ public async Task FiltersWithSubclassAsync()
6268
}
6369
s.Clear();
6470

65-
// TODO : currently impossible to define a collection-level filter w/
66-
// joined-subclass elements that will filter based on a superclass
67-
// column and function correctly in (theta only?) outer joins;
68-
// this is consistent with the behaviour of a collection-level where.
69-
// this might be one argument for "pulling" the attached class-level
70-
// filters into collection assocations,
71-
// although we'd need some way to apply the appropriate alias in that
72-
// scenario.
7371
results = (await (s.CreateQuery("from Person as p left join fetch p.Minions").ListAsync<Person>())).Distinct().ToList();
7472
Assert.AreEqual(4, results.Count, "Incorrect qry result count");
7573
foreach (Person p in results)
@@ -95,25 +93,12 @@ public async Task FiltersWithSubclassAsync()
9593
break;
9694
}
9795
}
98-
99-
await (t.CommitAsync());
100-
s.Close();
101-
102-
s = OpenSession();
103-
t = s.BeginTransaction();
104-
await (s.DeleteAsync("from Customer c where c.ContactOwner is not null"));
105-
await (s.DeleteAsync("from Employee e where e.Manager is not null"));
106-
await (s.DeleteAsync("from Person"));
107-
await (t.CommitAsync());
108-
s.Close();
10996
}
11097

11198
[Test]
11299
public async Task FilterCollectionWithSubclass1Async()
113100
{
114101
using var s = OpenSession();
115-
using var t = s.BeginTransaction();
116-
await (PrepareTestDataAsync(s));
117102

118103
s.EnableFilter("minionsWithManager");
119104

@@ -122,22 +107,18 @@ public async Task FilterCollectionWithSubclass1Async()
122107
Assert.That(employees[0].Minions.Count, Is.EqualTo(2));
123108
}
124109

125-
[KnownBug("GH-3079: Collection filter on subclass columns")]
126-
[Test]
110+
[Test(Description = "GH-3079: Collection filter on subclass columns")]
127111
public async Task FilterCollectionWithSubclass2Async()
128112
{
129113
using var s = OpenSession();
130-
using var t = s.BeginTransaction();
131-
await (PrepareTestDataAsync(s));
132-
133114
s.EnableFilter("minionsRegion").SetParameter("userRegion", "US");
134115

135116
var employees = await (s.Query<Employee>().Where(x => x.Minions.Any()).ToListAsync());
136117
Assert.That(employees.Count, Is.EqualTo(1));
137118
Assert.That(employees[0].Minions.Count, Is.EqualTo(1));
138119
}
139120

140-
private static async Task PrepareTestDataAsync(ISession s, CancellationToken cancellationToken = default(CancellationToken))
121+
private static void PrepareTestData(ISession s)
141122
{
142123
Employee john = new Employee("John Doe");
143124
john.Company = ("JBoss");
@@ -170,11 +151,9 @@ public async Task FilterCollectionWithSubclass2Async()
170151
ups.Company = ("UPS");
171152
ups.Region = ("US");
172153

173-
await (s.SaveAsync(john, cancellationToken));
174-
await (s.SaveAsync(cust, cancellationToken));
175-
await (s.SaveAsync(ups, cancellationToken));
176-
177-
await (s.FlushAsync(cancellationToken));
154+
s.Save(john);
155+
s.Save(cust);
156+
s.Save(ups);
178157
}
179158
}
180159
}

src/NHibernate.Test/SubclassFilterTest/JoinedSubclassFilterTest.cs

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Collections;
32
using NUnit.Framework;
43
using System.Linq;
@@ -8,25 +7,33 @@ namespace NHibernate.Test.SubclassFilterTest
87
[TestFixture]
98
public class JoinedSubclassFilterTest : TestCase
109
{
11-
protected override string[] Mappings
10+
protected override string[] Mappings => new[] {"SubclassFilterTest.joined-subclass.hbm.xml"};
11+
12+
protected override string MappingsAssembly => "NHibernate.Test";
13+
14+
protected override void OnSetUp()
1215
{
13-
get { return new string[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; }
16+
using var s = OpenSession();
17+
using var t = s.BeginTransaction();
18+
PrepareTestData(s);
19+
t.Commit();
1420
}
1521

16-
protected override string MappingsAssembly
22+
protected override void OnTearDown()
1723
{
18-
get { return "NHibernate.Test"; }
24+
using var s = OpenSession();
25+
using var t = s.BeginTransaction();
26+
s.Delete("from Customer c where c.ContactOwner is not null");
27+
s.Delete("from Employee e where e.Manager is not null");
28+
s.Delete("from Person");
29+
t.Commit();
1930
}
2031

2132
[Test]
2233
public void FiltersWithSubclass()
2334
{
24-
ISession s = OpenSession();
35+
using var s = OpenSession();
2536
s.EnableFilter("region").SetParameter("userRegion", "US");
26-
ITransaction t = s.BeginTransaction();
27-
28-
PrepareTestData(s);
29-
s.Clear();
3037

3138
IList results;
3239

@@ -49,14 +56,6 @@ public void FiltersWithSubclass()
4956
}
5057
s.Clear();
5158

52-
// TODO : currently impossible to define a collection-level filter w/
53-
// joined-subclass elements that will filter based on a superclass
54-
// column and function correctly in (theta only?) outer joins;
55-
// this is consistent with the behaviour of a collection-level where.
56-
// this might be one argument for "pulling" the attached class-level
57-
// filters into collection assocations,
58-
// although we'd need some way to apply the appropriate alias in that
59-
// scenario.
6059
results = s.CreateQuery("from Person as p left join fetch p.Minions").List<Person>().Distinct().ToList();
6160
Assert.AreEqual(4, results.Count, "Incorrect qry result count");
6261
foreach (Person p in results)
@@ -82,25 +81,12 @@ public void FiltersWithSubclass()
8281
break;
8382
}
8483
}
85-
86-
t.Commit();
87-
s.Close();
88-
89-
s = OpenSession();
90-
t = s.BeginTransaction();
91-
s.Delete("from Customer c where c.ContactOwner is not null");
92-
s.Delete("from Employee e where e.Manager is not null");
93-
s.Delete("from Person");
94-
t.Commit();
95-
s.Close();
9684
}
9785

9886
[Test]
9987
public void FilterCollectionWithSubclass1()
10088
{
10189
using var s = OpenSession();
102-
using var t = s.BeginTransaction();
103-
PrepareTestData(s);
10490

10591
s.EnableFilter("minionsWithManager");
10692

@@ -109,14 +95,10 @@ public void FilterCollectionWithSubclass1()
10995
Assert.That(employees[0].Minions.Count, Is.EqualTo(2));
11096
}
11197

112-
[KnownBug("GH-3079: Collection filter on subclass columns")]
113-
[Test]
98+
[Test(Description = "GH-3079: Collection filter on subclass columns")]
11499
public void FilterCollectionWithSubclass2()
115100
{
116101
using var s = OpenSession();
117-
using var t = s.BeginTransaction();
118-
PrepareTestData(s);
119-
120102
s.EnableFilter("minionsRegion").SetParameter("userRegion", "US");
121103

122104
var employees = s.Query<Employee>().Where(x => x.Minions.Any()).ToList();
@@ -160,8 +142,6 @@ private static void PrepareTestData(ISession s)
160142
s.Save(john);
161143
s.Save(cust);
162144
s.Save(ups);
163-
164-
s.Flush();
165145
}
166146
}
167147
}

src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,10 +1503,16 @@ protected virtual string FilterFragment(string alias)
15031503

15041504
public virtual string FilterFragment(string alias, IDictionary<string, IFilter> enabledFilters)
15051505
{
1506+
var filterFragment = FilterFragment(alias);
1507+
if (!filterHelper.IsAffectedBy(enabledFilters))
1508+
return filterFragment;
1509+
1510+
if (ElementType.IsEntityType && elementPersister is AbstractEntityPersister ep)
1511+
return ep.FilterFragment(filterHelper, alias, enabledFilters, filterFragment);
1512+
15061513
StringBuilder sessionFilterFragment = new StringBuilder();
15071514
filterHelper.Render(sessionFilterFragment, alias, enabledFilters);
1508-
1509-
return sessionFilterFragment.Append(FilterFragment(alias)).ToString();
1515+
return sessionFilterFragment.Append(filterFragment).ToString();
15101516
}
15111517

15121518
public string OneToManyFilterFragment(string alias)

src/NHibernate/Persister/Entity/AbstractEntityPersister.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3729,6 +3729,12 @@ public virtual string FilterFragment(string alias, IDictionary<string, IFilter>
37293729
if (!filterHelper.IsAffectedBy(enabledFilters))
37303730
return filterFragment;
37313731

3732+
return FilterFragment(filterHelper, alias, enabledFilters, filterFragment);
3733+
}
3734+
3735+
//TODO 6.0: Move to IEntityPersister and adjust usages accordingly
3736+
public virtual string FilterFragment(FilterHelper filterHelper, string alias, IDictionary<string, IFilter> enabledFilters, string filterFragment)
3737+
{
37323738
var sessionFilterFragment = new StringBuilder();
37333739
filterHelper.Render(sessionFilterFragment, GenerateFilterConditionAlias(alias), GetColumnsToTableAliasMap(alias), enabledFilters);
37343740
return sessionFilterFragment.Append(filterFragment).ToString();

0 commit comments

Comments
 (0)