@@ -320,10 +320,18 @@ private async Task<IList> DoQueryAsync(ISessionImplementor session, QueryParamet
320320 }
321321 }
322322
323- internal async Task InitializeEntitiesAndCollectionsAsync ( IList hydratedObjects , object resultSetId , ISessionImplementor session , bool readOnly , CancellationToken cancellationToken )
323+ internal Task InitializeEntitiesAndCollectionsAsync ( IList hydratedObjects , DbDataReader resultSetId , ISessionImplementor session , bool readOnly , CancellationToken cancellationToken )
324+ {
325+ if ( cancellationToken . IsCancellationRequested )
326+ {
327+ return Task . FromCanceled < object > ( cancellationToken ) ;
328+ }
329+ return InitializeEntitiesAndCollectionsAsync ( hydratedObjects , resultSetId , session , readOnly , CollectionPersisters , cancellationToken ) ;
330+ }
331+
332+ internal static async Task InitializeEntitiesAndCollectionsAsync ( IList hydratedObjects , DbDataReader resultSetId , ISessionImplementor session , bool readOnly , ICollectionPersister [ ] collectionPersisters , CancellationToken cancellationToken )
324333 {
325334 cancellationToken . ThrowIfCancellationRequested ( ) ;
326- ICollectionPersister [ ] collectionPersisters = CollectionPersisters ;
327335 if ( collectionPersisters != null )
328336 {
329337 for ( int i = 0 ; i < collectionPersisters . Length ; i ++ )
@@ -543,7 +551,7 @@ private async Task<EntityKey> GetKeyFromResultSetAsync(int i, IEntityPersister p
543551 /// if the version numbers are different.
544552 /// </summary>
545553 /// <exception cref="StaleObjectStateException"></exception>
546- private async Task CheckVersionAsync ( int i , IEntityPersister persister , object id , object entity , DbDataReader rs , ISessionImplementor session , CancellationToken cancellationToken )
554+ private static async Task CheckVersionAsync ( IEntityPersister persister , object id , object entity , DbDataReader rs , ISessionImplementor session , IEntityAliases entityAliases , CancellationToken cancellationToken )
547555 {
548556 cancellationToken . ThrowIfCancellationRequested ( ) ;
549557 object version = session . PersistenceContext . GetEntry ( entity ) . Version ;
@@ -552,7 +560,7 @@ private async Task CheckVersionAsync(int i, IEntityPersister persister, object i
552560 if ( version != null )
553561 {
554562 IVersionType versionType = persister . VersionType ;
555- object currentVersion = await ( versionType . NullSafeGetAsync ( rs , EntityAliases [ i ] . SuffixedVersionAliases , session , null , cancellationToken ) ) . ConfigureAwait ( false ) ;
563+ object currentVersion = await ( versionType . NullSafeGetAsync ( rs , entityAliases . SuffixedVersionAliases , session , null , cancellationToken ) ) . ConfigureAwait ( false ) ;
556564 if ( ! versionType . IsEqual ( version , currentVersion ) )
557565 {
558566 if ( session . Factory . Statistics . IsStatisticsEnabled )
@@ -577,7 +585,6 @@ private async Task<object[]> GetRowAsync(DbDataReader rs, ILoadable[] persisters
577585 {
578586 cancellationToken . ThrowIfCancellationRequested ( ) ;
579587 int cols = persisters . Length ;
580- IEntityAliases [ ] descriptors = EntityAliases ;
581588
582589 if ( Log . IsDebugEnabled ( ) )
583590 {
@@ -586,6 +593,7 @@ private async Task<object[]> GetRowAsync(DbDataReader rs, ILoadable[] persisters
586593
587594 object [ ] rowResults = new object [ cols ] ;
588595
596+ var upgradeLocks = UpgradeLocks ( ) ;
589597 for ( int i = 0 ; i < cols ; i ++ )
590598 {
591599 object obj = null ;
@@ -601,31 +609,62 @@ private async Task<object[]> GetRowAsync(DbDataReader rs, ILoadable[] persisters
601609 }
602610 else
603611 {
604- //If the object is already loaded, return the loaded one
605- obj = await ( session . GetEntityUsingInterceptorAsync ( key , cancellationToken ) ) . ConfigureAwait ( false ) ;
606- if ( obj != null )
607- {
608- //its already loaded so dont need to hydrate it
609- await ( InstanceAlreadyLoadedAsync ( rs , i , persisters [ i ] , key , obj , lockModes [ i ] , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
610- }
611- else
612- {
613- obj =
614- await ( InstanceNotYetLoadedAsync ( rs , i , persisters [ i ] , key , lockModes [ i ] , descriptors [ i ] . RowIdAlias , optionalObjectKey ,
615- optionalObject , hydratedObjects , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
616- }
612+ obj = await ( GetOrCreateEntityFromDataReaderAsync (
613+ rs ,
614+ optionalObject ,
615+ optionalObjectKey ,
616+ hydratedObjects ,
617+ session ,
618+ key ,
619+ persisters [ i ] ,
620+ lockModes [ i ] ,
621+ EntityAliases [ i ] ,
622+ upgradeLocks ,
623+ IsEagerPropertyFetchEnabled ( i ) ,
624+ OwnerAssociationTypes ? [ i ] , cancellationToken ) ) . ConfigureAwait ( false ) ;
617625 }
618626
619627 rowResults [ i ] = obj ;
620628 }
621629 return rowResults ;
622630 }
623631
632+ /// <summary>
633+ /// Returns either already loaded entity from session or creates new entity from data reader. Returned created entity is not fully initialized - it's added to <paramref name="hydratedObjects"/> collection. To fully initialize entity this collection needs to be supplied to <see cref="InitializeEntitiesAndCollectionsAsync(System.Collections.IList,System.Data.Common.DbDataReader,NHibernate.Engine.ISessionImplementor,bool,CancellationToken)"/>
634+ /// </summary>
635+ internal static async Task < object > GetOrCreateEntityFromDataReaderAsync ( DbDataReader rs , object optionalObject , EntityKey optionalObjectKey , IList hydratedObjects , ISessionImplementor session , EntityKey key , ILoadable persister , LockMode lockMode , IEntityAliases entityAliases , bool upgradeLocks , bool eagerPropertyFetch , EntityType ownerAssociationType , CancellationToken cancellationToken )
636+ {
637+ cancellationToken . ThrowIfCancellationRequested ( ) ;
638+ //If the object is already loaded, return the loaded one
639+ object obj = await ( session . GetEntityUsingInterceptorAsync ( key , cancellationToken ) ) . ConfigureAwait ( false ) ;
640+ if ( obj != null )
641+ {
642+ //its already loaded so dont need to hydrate it
643+ await ( InstanceAlreadyLoadedAsync ( rs , persister , key , obj , lockMode , session , entityAliases , upgradeLocks , cancellationToken ) ) . ConfigureAwait ( false ) ;
644+ }
645+ else
646+ {
647+ obj =
648+ await ( InstanceNotYetLoadedAsync (
649+ rs ,
650+ persister ,
651+ key ,
652+ lockMode ,
653+ optionalObjectKey ,
654+ optionalObject ,
655+ hydratedObjects ,
656+ session ,
657+ entityAliases ,
658+ eagerPropertyFetch ,
659+ ownerAssociationType , cancellationToken ) ) . ConfigureAwait ( false ) ;
660+ }
661+ return obj ;
662+ }
663+
624664 /// <summary>
625665 /// The entity instance is already in the session cache
626666 /// </summary>
627- private async Task InstanceAlreadyLoadedAsync ( DbDataReader rs , int i , IEntityPersister persister , EntityKey key , object obj ,
628- LockMode lockMode , ISessionImplementor session , CancellationToken cancellationToken )
667+ private static async Task InstanceAlreadyLoadedAsync ( DbDataReader rs , IEntityPersister persister , EntityKey key , object obj , LockMode lockMode , ISessionImplementor session , IEntityAliases entityAliases , bool upgradeLocks , CancellationToken cancellationToken )
629668 {
630669 cancellationToken . ThrowIfCancellationRequested ( ) ;
631670 if ( ! persister . IsInstance ( obj ) )
@@ -634,7 +673,7 @@ private async Task InstanceAlreadyLoadedAsync(DbDataReader rs, int i, IEntityPer
634673 throw new WrongClassException ( errorMsg , key . Identifier , persister . EntityName ) ;
635674 }
636675
637- if ( LockMode . None != lockMode && UpgradeLocks ( ) )
676+ if ( LockMode . None != lockMode && upgradeLocks )
638677 {
639678 EntityEntry entry = session . PersistenceContext . GetEntry ( obj ) ;
640679 bool isVersionCheckNeeded = persister . IsVersioned && entry . LockMode . LessThan ( lockMode ) ;
@@ -645,7 +684,7 @@ private async Task InstanceAlreadyLoadedAsync(DbDataReader rs, int i, IEntityPer
645684 if ( isVersionCheckNeeded )
646685 {
647686 // we only check the version when _upgrading_ lock modes
648- await ( CheckVersionAsync ( i , persister , key . Identifier , obj , rs , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
687+ await ( CheckVersionAsync ( persister , key . Identifier , obj , rs , session , entityAliases , cancellationToken ) ) . ConfigureAwait ( false ) ;
649688 // we need to upgrade the lock mode to the mode requested
650689 entry . LockMode = lockMode ;
651690 }
@@ -655,14 +694,12 @@ private async Task InstanceAlreadyLoadedAsync(DbDataReader rs, int i, IEntityPer
655694 /// <summary>
656695 /// The entity instance is not in the session cache
657696 /// </summary>
658- private async Task < object > InstanceNotYetLoadedAsync ( DbDataReader dr , int i , ILoadable persister , EntityKey key , LockMode lockMode ,
659- string rowIdAlias , EntityKey optionalObjectKey , object optionalObject ,
660- IList hydratedObjects , ISessionImplementor session , CancellationToken cancellationToken )
697+ private static async Task < object > InstanceNotYetLoadedAsync ( DbDataReader dr , ILoadable persister , EntityKey key , LockMode lockMode , EntityKey optionalObjectKey , object optionalObject , IList hydratedObjects , ISessionImplementor session , IEntityAliases entityAliases , bool eagerPropertyFetch , EntityType ownerAssociationType , CancellationToken cancellationToken )
661698 {
662699 cancellationToken . ThrowIfCancellationRequested ( ) ;
663700 object obj ;
664701
665- string instanceClass = await ( GetInstanceClassAsync ( dr , i , persister , key . Identifier , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
702+ string instanceClass = await ( GetInstanceClassAsync ( dr , persister , key . Identifier , session , entityAliases , cancellationToken ) ) . ConfigureAwait ( false ) ;
666703
667704 if ( optionalObjectKey != null && key . Equals ( optionalObjectKey ) )
668705 {
@@ -680,7 +717,7 @@ private async Task<object> InstanceNotYetLoadedAsync(DbDataReader dr, int i, ILo
680717 // (but don't yet initialize the object itself)
681718 // note that we acquired LockMode.READ even if it was not requested
682719 LockMode acquiredLockMode = lockMode == LockMode . None ? LockMode . Read : lockMode ;
683- await ( LoadFromResultSetAsync ( dr , i , obj , instanceClass , key , rowIdAlias , acquiredLockMode , persister , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
720+ await ( LoadFromResultSetAsync ( dr , obj , instanceClass , key , acquiredLockMode , persister , session , eagerPropertyFetch , entityAliases , ownerAssociationType , cancellationToken ) ) . ConfigureAwait ( false ) ;
684721
685722 // materialize associations (and initialize the object) later
686723 hydratedObjects . Add ( obj ) ;
@@ -693,41 +730,39 @@ private async Task<object> InstanceNotYetLoadedAsync(DbDataReader dr, int i, ILo
693730 /// an array of "hydrated" values (do not resolve associations yet),
694731 /// and pass the hydrated state to the session.
695732 /// </summary>
696- private async Task LoadFromResultSetAsync ( DbDataReader rs , int i , object obj , string instanceClass , EntityKey key ,
697- string rowIdAlias , LockMode lockMode , ILoadable rootPersister ,
698- ISessionImplementor session , CancellationToken cancellationToken )
733+ private static async Task LoadFromResultSetAsync ( DbDataReader rs , object obj , string instanceClass , EntityKey key , LockMode lockMode , ILoadable rootPersister ,
734+ ISessionImplementor session , bool eagerPropertyFetch , IEntityAliases entityAlias , EntityType ownerAssociationType , CancellationToken cancellationToken )
699735 {
700736 cancellationToken . ThrowIfCancellationRequested ( ) ;
701737 object id = key . Identifier ;
702738
703739 // Get the persister for the _subclass_
704- ILoadable persister = ( ILoadable ) Factory . GetEntityPersister ( instanceClass ) ;
740+ ILoadable persister = rootPersister . HasSubclasses
741+ ? ( ILoadable ) session . Factory . GetEntityPersister ( instanceClass )
742+ : rootPersister ;
705743
706744 if ( Log . IsDebugEnabled ( ) )
707745 {
708746 Log . Debug ( "Initializing object from DataReader: {0}" , MessageHelper . InfoString ( persister , id ) ) ;
709747 }
710748
711- bool eagerPropertyFetch = IsEagerPropertyFetchEnabled ( i ) ;
712-
713749 // add temp entry so that the next step is circular-reference
714750 // safe - only needed because some types don't take proper
715751 // advantage of two-phase-load (esp. components)
716752 TwoPhaseLoad . AddUninitializedEntity ( key , obj , persister , lockMode , ! eagerPropertyFetch , session ) ;
717753
718754 // This is not very nice (and quite slow):
719755 string [ ] [ ] cols = persister == rootPersister
720- ? EntityAliases [ i ] . SuffixedPropertyAliases
721- : EntityAliases [ i ] . GetSuffixedPropertyAliases ( persister ) ;
756+ ? entityAlias . SuffixedPropertyAliases
757+ : entityAlias . GetSuffixedPropertyAliases ( persister ) ;
722758
723759 object [ ] values = await ( persister . HydrateAsync ( rs , id , obj , rootPersister , cols , eagerPropertyFetch , session , cancellationToken ) ) . ConfigureAwait ( false ) ;
724760
725- object rowId = persister . HasRowId ? rs [ rowIdAlias ] : null ;
761+ object rowId = persister . HasRowId ? rs [ entityAlias . RowIdAlias ] : null ;
726762
727- IAssociationType [ ] ownerAssociationTypes = OwnerAssociationTypes ;
728- if ( ownerAssociationTypes != null && ownerAssociationTypes [ i ] != null )
763+ if ( ownerAssociationType != null )
729764 {
730- string ukName = ownerAssociationTypes [ i ] . RHSUniqueKeyPropertyName ;
765+ string ukName = ownerAssociationType . RHSUniqueKeyPropertyName ;
731766 if ( ukName != null )
732767 {
733768 int index = ( ( IUniqueKeyLoadable ) persister ) . GetPropertyIndex ( ukName ) ;
@@ -750,14 +785,14 @@ private async Task LoadFromResultSetAsync(DbDataReader rs, int i, object obj, st
750785 /// <summary>
751786 /// Determine the concrete class of an instance for the <c>DbDataReader</c>
752787 /// </summary>
753- private async Task < string > GetInstanceClassAsync ( DbDataReader rs , int i , ILoadable persister , object id , ISessionImplementor session , CancellationToken cancellationToken )
788+ private static async Task < string > GetInstanceClassAsync ( DbDataReader rs , ILoadable persister , object id , ISessionImplementor session , IEntityAliases entityAliases , CancellationToken cancellationToken )
754789 {
755790 cancellationToken . ThrowIfCancellationRequested ( ) ;
756791 if ( persister . HasSubclasses )
757792 {
758793 // code to handle subclasses of topClass
759794 object discriminatorValue =
760- await ( persister . DiscriminatorType . NullSafeGetAsync ( rs , EntityAliases [ i ] . SuffixedDiscriminatorAlias , session , null , cancellationToken ) ) . ConfigureAwait ( false ) ;
795+ await ( persister . DiscriminatorType . NullSafeGetAsync ( rs , entityAliases . SuffixedDiscriminatorAlias , session , null , cancellationToken ) ) . ConfigureAwait ( false ) ;
761796
762797 string result = persister . GetSubclassForDiscriminatorValue ( discriminatorValue ) ;
763798
0 commit comments