10
10
11
11
using System ;
12
12
using System . Linq ;
13
+ using System . Reflection ;
13
14
using NHibernate . Cfg ;
14
15
using NHibernate . Cfg . MappingSchema ;
15
16
using NHibernate . Collection ;
17
+ using NHibernate . Engine . Query ;
16
18
using NHibernate . Mapping . ByCode ;
19
+ using NHibernate . Util ;
17
20
using NUnit . Framework ;
18
21
using NHibernate . Linq ;
19
22
20
23
namespace NHibernate . Test . NHSpecificTest . NH2319
21
24
{
22
25
using System . Threading . Tasks ;
26
+ using System . Threading ;
23
27
[ TestFixture ]
24
28
public abstract class FixtureBaseAsync : TestCaseMappingByCode
25
29
{
26
- private Guid _parentId ;
30
+ private Guid _parent1Id ;
27
31
private Guid _child1Id ;
32
+ private Guid _parent2Id ;
33
+ private Guid _child3Id ;
28
34
29
35
[ Test ]
30
- public async Task ShouldBeAbleToFindChildrenByNameAsync ( )
36
+ public Task ShouldBeAbleToFindChildrenByNameAsync ( )
37
+ {
38
+ return FindChildrenByNameAsync ( _parent1Id , _child1Id ) ;
39
+ }
40
+
41
+ private async Task FindChildrenByNameAsync ( Guid parentId , Guid childId , CancellationToken cancellationToken = default ( CancellationToken ) )
31
42
{
32
43
using ( var session = OpenSession ( ) )
33
44
using ( session . BeginTransaction ( ) )
34
45
{
35
- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
46
+ var parent = await ( session . GetAsync < Parent > ( parentId , cancellationToken ) ) ;
36
47
37
48
Assert . That ( parent , Is . Not . Null ) ;
38
49
39
50
var filtered = await ( parent . Children
40
51
. AsQueryable ( )
41
52
. Where ( x => x . Name == "Jack" )
42
- . ToListAsync ( ) ) ;
53
+ . ToListAsync ( cancellationToken ) ) ;
43
54
44
55
Assert . That ( filtered , Has . Count . EqualTo ( 1 ) ) ;
45
- Assert . That ( filtered [ 0 ] . Id , Is . EqualTo ( _child1Id ) ) ;
56
+ Assert . That ( filtered [ 0 ] . Id , Is . EqualTo ( childId ) ) ;
46
57
}
47
58
}
48
59
@@ -52,7 +63,7 @@ public async Task ShouldBeAbleToPerformComplexFilteringAsync()
52
63
using ( var session = OpenSession ( ) )
53
64
using ( session . BeginTransaction ( ) )
54
65
{
55
- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
66
+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
56
67
57
68
Assert . NotNull ( parent ) ;
58
69
@@ -67,13 +78,35 @@ public async Task ShouldBeAbleToPerformComplexFilteringAsync()
67
78
}
68
79
}
69
80
81
+ [ Test ]
82
+ public async Task ShouldBeAbleToReuseQueryPlanAsync ( )
83
+ {
84
+ await ( ShouldBeAbleToFindChildrenByNameAsync ( ) ) ;
85
+ using ( var spy = new LogSpy ( typeof ( QueryPlanCache ) ) )
86
+ {
87
+ Assert . That ( ShouldBeAbleToFindChildrenByNameAsync , Throws . Nothing ) ;
88
+ AssertFilterPlanCacheHit ( spy ) ;
89
+ }
90
+ }
91
+
92
+ [ Test ]
93
+ public async Task ShouldNotMixResultsAsync ( )
94
+ {
95
+ await ( FindChildrenByNameAsync ( _parent1Id , _child1Id ) ) ;
96
+ using ( var spy = new LogSpy ( typeof ( QueryPlanCache ) ) )
97
+ {
98
+ await ( FindChildrenByNameAsync ( _parent2Id , _child3Id ) ) ;
99
+ AssertFilterPlanCacheHit ( spy ) ;
100
+ }
101
+ }
102
+
70
103
[ Test ]
71
104
public async Task ShouldNotInitializeCollectionWhenPerformingQueryAsync ( )
72
105
{
73
106
using ( var session = OpenSession ( ) )
74
107
using ( session . BeginTransaction ( ) )
75
108
{
76
- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
109
+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
77
110
Assert . That ( parent , Is . Not . Null ) ;
78
111
79
112
var persistentCollection = ( IPersistentCollection ) parent . Children ;
@@ -94,7 +127,7 @@ public async Task ShouldPerformSqlQueryEvenIfCollectionAlreadyInitializedAsync()
94
127
using ( var session = OpenSession ( ) )
95
128
using ( session . BeginTransaction ( ) )
96
129
{
97
- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
130
+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
98
131
Assert . That ( parent , Is . Not . Null ) ;
99
132
100
133
var loaded = parent . Children . ToList ( ) ;
@@ -120,7 +153,7 @@ public async Task TestFilterAsync()
120
153
using ( var session = OpenSession ( ) )
121
154
using ( session . BeginTransaction ( ) )
122
155
{
123
- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
156
+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
124
157
Assert . That ( parent , Is . Not . Null ) ;
125
158
126
159
var children = await ( ( await ( session . CreateFilterAsync ( parent . Children , "where this.Name = 'Jack'" ) ) )
@@ -130,6 +163,35 @@ public async Task TestFilterAsync()
130
163
}
131
164
}
132
165
166
+ [ Test ]
167
+ public async Task TestPlanCacheMissAsync ( )
168
+ {
169
+ var internalPlanCache = typeof ( QueryPlanCache )
170
+ . GetField ( "planCache" , BindingFlags . NonPublic | BindingFlags . Instance )
171
+ ? . GetValue ( Sfi . QueryPlanCache ) as SoftLimitMRUCache ;
172
+ Assert . That ( internalPlanCache , Is . Not . Null ,
173
+ $ "Unable to find the internal query plan cache for clearing it, please adapt code to current { nameof ( QueryPlanCache ) } implementation.") ;
174
+
175
+ using ( var spy = new LogSpy ( typeof ( QueryPlanCache ) ) )
176
+ {
177
+ internalPlanCache . Clear ( ) ;
178
+ await ( ShouldBeAbleToFindChildrenByNameAsync ( ) ) ;
179
+ AssertFilterPlanCacheMiss ( spy ) ;
180
+ }
181
+ }
182
+
183
+ private const string _filterPlanCacheMissLog = "unable to locate collection-filter query plan in cache" ;
184
+
185
+ private static void AssertFilterPlanCacheHit ( LogSpy spy ) =>
186
+ // Each query currently ask the cache two times, so asserting reuse requires to check cache has not been missed
187
+ // rather than only asserting it has been hit.
188
+ Assert . That ( spy . GetWholeLog ( ) ,
189
+ Contains . Substring ( "located collection-filter query plan in cache (" )
190
+ . And . Not . Contains ( _filterPlanCacheMissLog ) ) ;
191
+
192
+ private static void AssertFilterPlanCacheMiss ( LogSpy spy ) =>
193
+ Assert . That ( spy . GetWholeLog ( ) , Contains . Substring ( _filterPlanCacheMissLog ) ) ;
194
+
133
195
protected override void Configure ( Configuration configuration )
134
196
{
135
197
configuration . SetProperty ( "show_sql" , "true" ) ;
@@ -141,11 +203,11 @@ protected override void OnSetUp()
141
203
using ( var session = OpenSession ( ) )
142
204
using ( var transaction = session . BeginTransaction ( ) )
143
205
{
144
- var parent1 = new Parent { Name = "Bob" } ;
145
- _parentId = ( Guid ) session . Save ( parent1 ) ;
206
+ var parent1 = new Parent { Name = "Bob" } ;
207
+ _parent1Id = ( Guid ) session . Save ( parent1 ) ;
146
208
147
- var parent2 = new Parent { Name = "Martin" } ;
148
- session . Save ( parent2 ) ;
209
+ var parent2 = new Parent { Name = "Martin" } ;
210
+ _parent2Id = ( Guid ) session . Save ( parent2 ) ;
149
211
150
212
var child1 = new Child
151
213
{
@@ -185,7 +247,7 @@ protected override void OnSetUp()
185
247
Parent = parent2
186
248
} ;
187
249
parent2 . Children . Add ( child3 ) ;
188
- session . Save ( child3 ) ;
250
+ _child3Id = ( Guid ) session . Save ( child3 ) ;
189
251
190
252
session . Flush ( ) ;
191
253
transaction . Commit ( ) ;
0 commit comments