1010
1111using System ;
1212using System . Linq ;
13+ using System . Reflection ;
1314using NHibernate . Cfg ;
1415using NHibernate . Cfg . MappingSchema ;
1516using NHibernate . Collection ;
17+ using NHibernate . Engine . Query ;
1618using NHibernate . Mapping . ByCode ;
19+ using NHibernate . Util ;
1720using NUnit . Framework ;
1821using NHibernate . Linq ;
1922
2023namespace NHibernate . Test . NHSpecificTest . NH2319
2124{
2225 using System . Threading . Tasks ;
26+ using System . Threading ;
2327 [ TestFixture ]
2428 public abstract class FixtureBaseAsync : TestCaseMappingByCode
2529 {
26- private Guid _parentId ;
30+ private Guid _parent1Id ;
2731 private Guid _child1Id ;
32+ private Guid _parent2Id ;
33+ private Guid _child3Id ;
2834
2935 [ 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 ) )
3142 {
3243 using ( var session = OpenSession ( ) )
3344 using ( session . BeginTransaction ( ) )
3445 {
35- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
46+ var parent = await ( session . GetAsync < Parent > ( parentId , cancellationToken ) ) ;
3647
3748 Assert . That ( parent , Is . Not . Null ) ;
3849
3950 var filtered = await ( parent . Children
4051 . AsQueryable ( )
4152 . Where ( x => x . Name == "Jack" )
42- . ToListAsync ( ) ) ;
53+ . ToListAsync ( cancellationToken ) ) ;
4354
4455 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 ) ) ;
4657 }
4758 }
4859
@@ -52,7 +63,7 @@ public async Task ShouldBeAbleToPerformComplexFilteringAsync()
5263 using ( var session = OpenSession ( ) )
5364 using ( session . BeginTransaction ( ) )
5465 {
55- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
66+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
5667
5768 Assert . NotNull ( parent ) ;
5869
@@ -67,13 +78,35 @@ public async Task ShouldBeAbleToPerformComplexFilteringAsync()
6778 }
6879 }
6980
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+
70103 [ Test ]
71104 public async Task ShouldNotInitializeCollectionWhenPerformingQueryAsync ( )
72105 {
73106 using ( var session = OpenSession ( ) )
74107 using ( session . BeginTransaction ( ) )
75108 {
76- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
109+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
77110 Assert . That ( parent , Is . Not . Null ) ;
78111
79112 var persistentCollection = ( IPersistentCollection ) parent . Children ;
@@ -94,7 +127,7 @@ public async Task ShouldPerformSqlQueryEvenIfCollectionAlreadyInitializedAsync()
94127 using ( var session = OpenSession ( ) )
95128 using ( session . BeginTransaction ( ) )
96129 {
97- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
130+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
98131 Assert . That ( parent , Is . Not . Null ) ;
99132
100133 var loaded = parent . Children . ToList ( ) ;
@@ -120,7 +153,7 @@ public async Task TestFilterAsync()
120153 using ( var session = OpenSession ( ) )
121154 using ( session . BeginTransaction ( ) )
122155 {
123- var parent = await ( session . GetAsync < Parent > ( _parentId ) ) ;
156+ var parent = await ( session . GetAsync < Parent > ( _parent1Id ) ) ;
124157 Assert . That ( parent , Is . Not . Null ) ;
125158
126159 var children = await ( ( await ( session . CreateFilterAsync ( parent . Children , "where this.Name = 'Jack'" ) ) )
@@ -130,6 +163,33 @@ public async Task TestFilterAsync()
130163 }
131164 }
132165
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 static void AssertFilterPlanCacheHit ( LogSpy spy ) =>
184+ // Each query currently ask the cache two times, so asserting reuse requires to check cache has not been missed
185+ // rather than only asserting it has been hit.
186+ Assert . That ( spy . GetWholeLog ( ) ,
187+ Contains . Substring ( "located collection-filter query plan in cache (" )
188+ . And . Not . Contains ( _filterPlanCacheMissLog ) ) ;
189+
190+ private static void AssertFilterPlanCacheMiss ( LogSpy spy ) =>
191+ Assert . That ( spy . GetWholeLog ( ) , Contains . Substring ( _filterPlanCacheMissLog ) ) ;
192+
133193 protected override void Configure ( Configuration configuration )
134194 {
135195 configuration . SetProperty ( "show_sql" , "true" ) ;
@@ -141,11 +201,11 @@ protected override void OnSetUp()
141201 using ( var session = OpenSession ( ) )
142202 using ( var transaction = session . BeginTransaction ( ) )
143203 {
144- var parent1 = new Parent { Name = "Bob" } ;
145- _parentId = ( Guid ) session . Save ( parent1 ) ;
204+ var parent1 = new Parent { Name = "Bob" } ;
205+ _parent1Id = ( Guid ) session . Save ( parent1 ) ;
146206
147- var parent2 = new Parent { Name = "Martin" } ;
148- session . Save ( parent2 ) ;
207+ var parent2 = new Parent { Name = "Martin" } ;
208+ _parent2Id = ( Guid ) session . Save ( parent2 ) ;
149209
150210 var child1 = new Child
151211 {
@@ -185,7 +245,7 @@ protected override void OnSetUp()
185245 Parent = parent2
186246 } ;
187247 parent2 . Children . Add ( child3 ) ;
188- session . Save ( child3 ) ;
248+ _child3Id = ( Guid ) session . Save ( child3 ) ;
189249
190250 session . Flush ( ) ;
191251 transaction . Commit ( ) ;
0 commit comments