3636using Property = NHibernate . Mapping . Property ;
3737using NHibernate . SqlTypes ;
3838using System . Linq ;
39+ using System . Linq . Expressions ;
3940using NHibernate . Bytecode ;
4041
4142namespace NHibernate . Persister . Entity
@@ -101,7 +102,7 @@ async Task InternalInitializeLazyPropertiesAsync()
101102 }
102103 }
103104
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 ) ;
105106 for ( var i = 0 ; i < lazyIndexes . Length ; i ++ )
106107 {
107108 var value = values [ i ] ;
@@ -400,14 +401,14 @@ protected async Task<int> DehydrateAsync(object id, object[] fields, object rowI
400401 /// Unmarshall the fields of a persistent instance from a result set,
401402 /// without resolving associations or collections
402403 /// </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 ,
404405 string [ ] [ ] suffixedPropertyColumns , ISet < string > fetchedLazyProperties , bool allProperties , ISessionImplementor session , CancellationToken cancellationToken )
405406 {
406407 if ( cancellationToken . IsCancellationRequested )
407408 {
408409 return Task . FromCanceled < object [ ] > ( cancellationToken ) ;
409410 }
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 ) ;
411412 }
412413
413414 /// <summary>
@@ -423,14 +424,14 @@ public Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj, ILoad
423424 {
424425 return Task . FromCanceled < object [ ] > ( cancellationToken ) ;
425426 }
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 ) ;
427428 }
428429
429430 /// <summary>
430431 /// Unmarshall the fields of a persistent instance from a result set,
431432 /// without resolving associations or collections
432433 /// </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 ,
434435 ISet < string > fetchedLazyProperties , bool allProperties , int [ ] indexes , ISessionImplementor session , CancellationToken cancellationToken )
435436 {
436437 cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -439,49 +440,43 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
439440 log . Debug ( "Hydrating entity: {0}" , MessageHelper . InfoString ( this , id , Factory ) ) ;
440441 }
441442
442- AbstractEntityPersister rootPersister = ( AbstractEntityPersister ) rootLoadable ;
443-
444- bool hasDeferred = rootPersister . HasSequentialSelect ;
443+ var sequentialSql = GetSequentialSelect ( ) ;
445444 DbCommand sequentialSelect = null ;
446445 DbDataReader sequentialResultSet = null ;
447446 bool sequentialSelectEmpty = false ;
448447 using ( session . BeginProcess ( ) )
449448 try
450449 {
451- if ( hasDeferred )
450+ if ( sequentialSql != null )
452451 {
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 ) )
455457 {
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 ;
485480 }
486481 }
487482
@@ -491,7 +486,6 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
491486 IType [ ] types = PropertyTypes ;
492487 object [ ] values = new object [ length ] ;
493488 bool [ ] laziness = PropertyLaziness ;
494- string [ ] propSubclassNames = SubclassPropertySubclassNameClosure ;
495489
496490 for ( int j = 0 ; j < length ; j ++ )
497491 {
@@ -503,8 +497,7 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
503497 else if ( allProperties || ! laziness [ i ] || fetchedLazyProperties ? . Contains ( propNames [ i ] ) == true )
504498 {
505499 //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 ) ;
508501 if ( propertyIsDeferred && sequentialSelectEmpty )
509502 {
510503 values [ j ] = null ;
@@ -522,15 +515,11 @@ private async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj
522515 }
523516 }
524517
525- if ( sequentialResultSet != null )
526- {
527- sequentialResultSet . Close ( ) ;
528- }
529-
530518 return values ;
531519 }
532520 finally
533521 {
522+ sequentialResultSet ? . Close ( ) ;
534523 if ( sequentialSelect != null )
535524 {
536525 session . Batcher . CloseCommand ( sequentialSelect , sequentialResultSet ) ;
0 commit comments