36
36
using Property = NHibernate . Mapping . Property ;
37
37
using NHibernate . SqlTypes ;
38
38
using System . Linq ;
39
+ using System . Linq . Expressions ;
39
40
using NHibernate . Bytecode ;
40
41
41
42
namespace NHibernate . Persister . Entity
@@ -101,7 +102,7 @@ async Task InternalInitializeLazyPropertiesAsync()
101
102
}
102
103
}
103
104
104
- var values = await ( HydrateAsync ( rs , id , entity , rootPersister , suffixedPropertyColumns , null , true , indexes , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
105
+ var values = await ( HydrateAsync ( rs , id , entity , suffixedPropertyColumns , null , true , indexes , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
105
106
for ( var i = 0 ; i < lazyIndexes . Length ; i ++ )
106
107
{
107
108
var value = values [ i ] ;
@@ -400,14 +401,14 @@ protected async Task<int> DehydrateAsync(object id, object[] fields, object rowI
400
401
/// Unmarshall the fields of a persistent instance from a result set,
401
402
/// without resolving associations or collections
402
403
/// </summary>
403
- public Task < object [ ] > HydrateAsync ( DbDataReader rs , object id , object obj , ILoadable rootLoadable ,
404
+ public Task < object [ ] > HydrateAsync ( DbDataReader rs , object id , object obj ,
404
405
string [ ] [ ] suffixedPropertyColumns , ISet < string > fetchedLazyProperties , bool allProperties , ISessionImplementor session , CancellationToken cancellationToken )
405
406
{
406
407
if ( cancellationToken . IsCancellationRequested )
407
408
{
408
409
return Task . FromCanceled < object [ ] > ( cancellationToken ) ;
409
410
}
410
- return HydrateAsync ( rs , id , obj , rootLoadable , suffixedPropertyColumns , fetchedLazyProperties , allProperties , null , session , cancellationToken ) ;
411
+ return HydrateAsync ( rs , id , obj , suffixedPropertyColumns , fetchedLazyProperties , allProperties , null , session , cancellationToken ) ;
411
412
}
412
413
413
414
/// <summary>
@@ -423,14 +424,14 @@ public Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj, ILoad
423
424
{
424
425
return Task . FromCanceled < object [ ] > ( cancellationToken ) ;
425
426
}
426
- return HydrateAsync ( rs , id , obj , rootLoadable , suffixedPropertyColumns , null , allProperties , null , session , cancellationToken ) ;
427
+ return HydrateAsync ( rs , id , obj , suffixedPropertyColumns , null , allProperties , null , session , cancellationToken ) ;
427
428
}
428
429
429
430
/// <summary>
430
431
/// Unmarshall the fields of a persistent instance from a result set,
431
432
/// without resolving associations or collections
432
433
/// </summary>
433
- private async Task < object [ ] > HydrateAsync ( DbDataReader rs , object id , object obj , ILoadable rootLoadable , string [ ] [ ] suffixedPropertyColumns ,
434
+ private async Task < object [ ] > HydrateAsync ( DbDataReader rs , object id , object obj , string [ ] [ ] suffixedPropertyColumns ,
434
435
ISet < string > fetchedLazyProperties , bool allProperties , int [ ] indexes , ISessionImplementor session , CancellationToken cancellationToken )
435
436
{
436
437
cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -439,49 +440,43 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
439
440
log . Debug ( "Hydrating entity: {0}" , MessageHelper . InfoString ( this , id , Factory ) ) ;
440
441
}
441
442
442
- AbstractEntityPersister rootPersister = ( AbstractEntityPersister ) rootLoadable ;
443
-
444
- bool hasDeferred = rootPersister . HasSequentialSelect ;
443
+ var sequentialSql = GetSequentialSelect ( ) ;
445
444
DbCommand sequentialSelect = null ;
446
445
DbDataReader sequentialResultSet = null ;
447
446
bool sequentialSelectEmpty = false ;
448
447
using ( session . BeginProcess ( ) )
449
448
try
450
449
{
451
- if ( hasDeferred )
450
+ if ( sequentialSql != null )
452
451
{
453
- SqlString sql = rootPersister . GetSequentialSelect ( EntityName ) ;
454
- if ( sql != null )
452
+ //TODO: I am not so sure about the exception handling in this bit!
453
+ sequentialSelect = await ( session . Batcher . PrepareCommandAsync ( CommandType . Text , sequentialSql , IdentifierType . SqlTypes ( factory ) , cancellationToken ) ) . ConfigureAwait ( false ) ;
454
+ await ( IdentifierType . NullSafeSetAsync ( sequentialSelect , id , 0 , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
455
+ sequentialResultSet = await ( session . Batcher . ExecuteReaderAsync ( sequentialSelect , cancellationToken ) ) . ConfigureAwait ( false ) ;
456
+ if ( ! await ( sequentialResultSet . ReadAsync ( cancellationToken ) ) . ConfigureAwait ( false ) )
455
457
{
456
- //TODO: I am not so sure about the exception handling in this bit!
457
- sequentialSelect = await ( session . Batcher . PrepareCommandAsync ( CommandType . Text , sql , IdentifierType . SqlTypes ( factory ) , cancellationToken ) ) . ConfigureAwait ( false ) ;
458
- await ( rootPersister . IdentifierType . NullSafeSetAsync ( sequentialSelect , id , 0 , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
459
- sequentialResultSet = await ( session . Batcher . ExecuteReaderAsync ( sequentialSelect , cancellationToken ) ) . ConfigureAwait ( false ) ;
460
- if ( ! await ( sequentialResultSet . ReadAsync ( cancellationToken ) ) . ConfigureAwait ( false ) )
461
- {
462
- // TODO: Deal with the "optional" attribute in the <join> mapping;
463
- // this code assumes that optional defaults to "true" because it
464
- // doesn't actually seem to work in the fetch="join" code
465
- //
466
- // Note that actual proper handling of optional-ality here is actually
467
- // more involved than this patch assumes. Remember that we might have
468
- // multiple <join/> mappings associated with a single entity. Really
469
- // a couple of things need to happen to properly handle optional here:
470
- // 1) First and foremost, when handling multiple <join/>s, we really
471
- // should be using the entity root table as the driving table;
472
- // another option here would be to choose some non-optional joined
473
- // table to use as the driving table. In all likelihood, just using
474
- // the root table is much simplier
475
- // 2) Need to add the FK columns corresponding to each joined table
476
- // to the generated select list; these would then be used when
477
- // iterating the result set to determine whether all non-optional
478
- // data is present
479
- // My initial thoughts on the best way to deal with this would be
480
- // to introduce a new SequentialSelect abstraction that actually gets
481
- // generated in the persisters (ok, SingleTable...) and utilized here.
482
- // It would encapsulated all this required optional-ality checking...
483
- sequentialSelectEmpty = true ;
484
- }
458
+ // TODO: Deal with the "optional" attribute in the <join> mapping;
459
+ // this code assumes that optional defaults to "true" because it
460
+ // doesn't actually seem to work in the fetch="join" code
461
+ //
462
+ // Note that actual proper handling of optional-ality here is actually
463
+ // more involved than this patch assumes. Remember that we might have
464
+ // multiple <join/> mappings associated with a single entity. Really
465
+ // a couple of things need to happen to properly handle optional here:
466
+ // 1) First and foremost, when handling multiple <join/>s, we really
467
+ // should be using the entity root table as the driving table;
468
+ // another option here would be to choose some non-optional joined
469
+ // table to use as the driving table. In all likelihood, just using
470
+ // the root table is much simplier
471
+ // 2) Need to add the FK columns corresponding to each joined table
472
+ // to the generated select list; these would then be used when
473
+ // iterating the result set to determine whether all non-optional
474
+ // data is present
475
+ // My initial thoughts on the best way to deal with this would be
476
+ // to introduce a new SequentialSelect abstraction that actually gets
477
+ // generated in the persisters (ok, SingleTable...) and utilized here.
478
+ // It would encapsulated all this required optional-ality checking...
479
+ sequentialSelectEmpty = true ;
485
480
}
486
481
}
487
482
@@ -491,7 +486,6 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
491
486
IType [ ] types = PropertyTypes ;
492
487
object [ ] values = new object [ length ] ;
493
488
bool [ ] laziness = PropertyLaziness ;
494
- string [ ] propSubclassNames = SubclassPropertySubclassNameClosure ;
495
489
496
490
for ( int j = 0 ; j < length ; j ++ )
497
491
{
@@ -503,8 +497,7 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
503
497
else if ( allProperties || ! laziness [ i ] || fetchedLazyProperties ? . Contains ( propNames [ i ] ) == true )
504
498
{
505
499
//decide which ResultSet to get the property value from:
506
- bool propertyIsDeferred = hasDeferred
507
- && rootPersister . IsSubclassPropertyDeferred ( propNames [ i ] , propSubclassNames [ i ] ) ;
500
+ var propertyIsDeferred = sequentialSql != null && IsPropertyDeferred ( i ) ;
508
501
if ( propertyIsDeferred && sequentialSelectEmpty )
509
502
{
510
503
values [ j ] = null ;
@@ -522,15 +515,11 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
522
515
}
523
516
}
524
517
525
- if ( sequentialResultSet != null )
526
- {
527
- sequentialResultSet . Close ( ) ;
528
- }
529
-
530
518
return values ;
531
519
}
532
520
finally
533
521
{
522
+ sequentialResultSet ? . Close ( ) ;
534
523
if ( sequentialSelect != null )
535
524
{
536
525
session . Batcher . CloseCommand ( sequentialSelect , sequentialResultSet ) ;
0 commit comments