5
5
// Created: 2009.12.24
6
6
7
7
using System ;
8
+ using System . Collections . Generic ;
8
9
using NUnit . Framework ;
9
10
using System . Linq ;
11
+ using System . Reflection ;
12
+ using System . Threading ;
10
13
using System . Threading . Tasks ;
11
- using Xtensive . Core ;
12
- using Xtensive . Orm . Internals . Prefetch ;
14
+ using Xtensive . Orm . Internals ;
15
+ using Xtensive . Orm . Providers ;
13
16
using Xtensive . Orm . Services ;
14
17
using Xtensive . Orm . Tests ;
15
18
@@ -44,7 +47,7 @@ public class Person : Entity
44
47
45
48
public Person ( Session session )
46
49
: base ( session )
47
- { }
50
+ { }
48
51
}
49
52
50
53
#endregion
@@ -63,10 +66,10 @@ protected override Configuration.DomainConfiguration BuildConfiguration()
63
66
[ TearDown ]
64
67
public void ClearContent ( )
65
68
{
66
- using ( var session = Domain . OpenSession ( ) )
67
- using ( var tx = session . OpenTransaction ( ) ) {
69
+ using ( var session = Domain . OpenSession ( ) )
70
+ using ( var tx = session . OpenTransaction ( ) ) {
68
71
var people = session . Query . All < Person > ( ) . ToList ( ) ;
69
- foreach ( var person in people ) {
72
+ foreach ( var person in people ) {
70
73
person . Manager = null ;
71
74
}
72
75
session . SaveChanges ( ) ;
@@ -247,7 +250,7 @@ public async Task MultipleBatchesAsyncTest()
247
250
var count = 1000 ;
248
251
249
252
await using ( var session = await Domain . OpenSessionAsync ( ) )
250
- using ( var transactionScope = session . OpenTransaction ( ) ) {
253
+ using ( var transactionScope = session . OpenTransaction ( ) ) {
251
254
var people = new Person [ count ] ;
252
255
for ( var i = 0 ; i < count ; i ++ ) {
253
256
people [ i ] = new Person ( session ) { Name = i . ToString ( ) , Photo = new [ ] { ( byte ) ( i % 256 ) } } ;
@@ -376,6 +379,98 @@ public async Task DelayedQueryAsyncTest()
376
379
}
377
380
}
378
381
382
+ private class QueryCounterSessionHandlerMoq : ChainingSessionHandler
383
+ {
384
+ private volatile int syncCounter ;
385
+ private volatile int asyncCounter ;
386
+
387
+ public int GetSyncCounter ( ) => syncCounter ;
388
+
389
+ public int GetAsyncCounter ( ) => asyncCounter ;
390
+
391
+ public QueryCounterSessionHandlerMoq ( SessionHandler chainedHandler ) : base ( chainedHandler )
392
+ {
393
+ }
394
+
395
+ public override void ExecuteQueryTasks ( IEnumerable < QueryTask > queryTasks , bool allowPartialExecution )
396
+ {
397
+ _ = Interlocked . Increment ( ref syncCounter ) ;
398
+ base . ExecuteQueryTasks ( queryTasks , allowPartialExecution ) ;
399
+ }
400
+
401
+ public override Task ExecuteQueryTasksAsync ( IEnumerable < QueryTask > queryTasks , bool allowPartialExecution , CancellationToken token )
402
+ {
403
+ _ = Interlocked . Increment ( ref asyncCounter ) ;
404
+ return base . ExecuteQueryTasksAsync ( queryTasks , allowPartialExecution , token ) ;
405
+ }
406
+ }
407
+
408
+ [ Test ]
409
+ public async Task DelayedQueryAsyncShouldMaterializeAsyncTest ( )
410
+ {
411
+ await using ( var session = await Domain . OpenSessionAsync ( ) ) {
412
+ using ( var transactionScope = session . OpenTransaction ( ) ) {
413
+ var employee = new Person ( session ) { Name = "Employee" , Photo = new byte [ ] { 8 , 0 } } ;
414
+ var manager = new Person ( session ) { Name = "Manager" , Photo = new byte [ ] { 8 , 0 } } ;
415
+ _ = manager . Employees . Add ( employee ) ;
416
+ transactionScope . Complete ( ) ;
417
+ }
418
+ }
419
+
420
+ await using ( var session = await Domain . OpenSessionAsync ( ) ) // no session activation!
421
+ {
422
+ var sessionAccessor = new DirectSessionAccessor ( session ) ;
423
+ var prop = typeof ( Session ) . GetProperty ( "Handler" , BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . GetProperty ) ;
424
+ var handler = prop . GetValue ( session ) as SessionHandler ;
425
+ var moq = new QueryCounterSessionHandlerMoq ( handler ) ;
426
+ using ( sessionAccessor . ChangeSessionHandler ( moq ) )
427
+
428
+ using ( var transactionScope = session . OpenTransaction ( ) ) {
429
+ var people = session . Query . CreateDelayedQuery ( q => q . All < Person > ( ) )
430
+ . Prefetch ( p => p . Photo ) // Lazy load field
431
+ . Prefetch ( p => p . Employees // EntitySet Employees
432
+ . Prefetch ( e => e . Photo ) ) // and lazy load field of each of its items
433
+ . Prefetch ( p => p . Manager ) ; // Referenced entity
434
+ foreach ( var person in people ) {
435
+ // some code here...
436
+ }
437
+ Assert . That ( moq . GetSyncCounter ( ) , Is . GreaterThan ( 0 ) ) ;
438
+ Assert . That ( moq . GetAsyncCounter ( ) , Is . EqualTo ( 0 ) ) ;
439
+ transactionScope . Complete ( ) ;
440
+ }
441
+ }
442
+
443
+ await using ( var session = await Domain . OpenSessionAsync ( ) ) // no session activation!
444
+ {
445
+ var sessionAccessor = new DirectSessionAccessor ( session ) ;
446
+ var prop = typeof ( Session ) . GetProperty ( "Handler" , BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . GetProperty ) ;
447
+ var handler = prop . GetValue ( session ) as SessionHandler ;
448
+ var moq = new QueryCounterSessionHandlerMoq ( handler ) ;
449
+ using ( sessionAccessor . ChangeSessionHandler ( moq ) )
450
+
451
+ using ( var transactionScope = session . OpenTransaction ( ) ) {
452
+ var people = session . Query . CreateDelayedQuery ( q => q . All < Person > ( ) )
453
+ . Prefetch ( p => p . Photo ) // Lazy load field
454
+ . Prefetch ( p => p . Employees . Prefetch ( e => e . Photo ) ) // EntitySet Employees and lazy load field of each of its items with the limit on number of items to be loaded
455
+ . Prefetch ( p => p . Manager . Photo ) ; // Referenced entity and lazy load field for each of them
456
+ await foreach ( var person in people . AsAsyncEnumerable ( ) ) {
457
+ var accessor = DirectStateAccessor . Get ( person ) ;
458
+ Assert . That ( accessor . GetFieldState ( "Photo" ) , Is . EqualTo ( PersistentFieldState . Loaded ) ) ;
459
+ Assert . That ( accessor . GetFieldState ( "Manager" ) , Is . EqualTo ( PersistentFieldState . Loaded ) ) ;
460
+ if ( person . ManagerKey != null ) {
461
+ Assert . IsNotNull ( DirectStateAccessor . Get ( session ) [ person . ManagerKey ] ) ;
462
+ Assert . That ( DirectStateAccessor . Get ( person . Manager ) . GetFieldState ( "Photo" ) , Is . EqualTo ( PersistentFieldState . Loaded ) ) ;
463
+ }
464
+ // some code here...
465
+ }
466
+ Assert . That ( moq . GetSyncCounter ( ) , Is . EqualTo ( 0 ) ) ;
467
+ Assert . That ( moq . GetAsyncCounter ( ) , Is . GreaterThan ( 0 ) ) ;
468
+ transactionScope . Complete ( ) ;
469
+ }
470
+
471
+ }
472
+ }
473
+
379
474
[ Test ]
380
475
public void CachedQueryTest ( )
381
476
{
0 commit comments