1
+ using System . Collections ;
2
+ using System . Collections . Generic ;
3
+ using System . Data . Common ;
4
+ using System . Diagnostics ;
5
+ using NHibernate . Cache ;
6
+ using NHibernate . Cache . Entry ;
7
+ using NHibernate . Collection ;
8
+ using NHibernate . Impl ;
9
+ using NHibernate . Persister . Collection ;
10
+ using System . Threading . Tasks ;
11
+
12
+ namespace NHibernate . Engine . Loading
13
+ {
14
+ [ System . CodeDom . Compiler . GeneratedCode ( "AsyncGenerator" , "1.0.0" ) ]
15
+ public partial class CollectionLoadContext
16
+ {
17
+ /// <summary>
18
+ /// Finish the process of collection-loading for this bound result set. Mainly this
19
+ /// involves cleaning up resources and notifying the collections that loading is
20
+ /// complete.
21
+ /// </summary>
22
+ /// <param name = "persister">The persister for which to complete loading. </param>
23
+ public async Task EndLoadingCollectionsAsync ( ICollectionPersister persister )
24
+ {
25
+ if ( ! loadContexts . HasLoadingCollectionEntries && ( localLoadingCollectionKeys . Count == 0 ) )
26
+ {
27
+ return ;
28
+ }
29
+
30
+ // in an effort to avoid concurrent-modification-exceptions (from
31
+ // potential recursive calls back through here as a result of the
32
+ // eventual call to PersistentCollection#endRead), we scan the
33
+ // internal loadingCollections map for matches and store those matches
34
+ // in a temp collection. the temp collection is then used to "drive"
35
+ // the #endRead processing.
36
+ List < CollectionKey > toRemove = new List < CollectionKey > ( ) ;
37
+ List < LoadingCollectionEntry > matches = new List < LoadingCollectionEntry > ( ) ;
38
+ foreach ( CollectionKey collectionKey in localLoadingCollectionKeys )
39
+ {
40
+ ISessionImplementor session = LoadContext . PersistenceContext . Session ;
41
+ LoadingCollectionEntry lce = loadContexts . LocateLoadingCollectionEntry ( collectionKey ) ;
42
+ if ( lce == null )
43
+ {
44
+ log . Warn ( "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [" + collectionKey + "], but no LoadingCollectionEntry was found in loadContexts" ) ;
45
+ }
46
+ else if ( lce . ResultSet == resultSet && lce . Persister == persister )
47
+ {
48
+ matches . Add ( lce ) ;
49
+ if ( lce . Collection . Owner == null )
50
+ {
51
+ session . PersistenceContext . AddUnownedCollection ( new CollectionKey ( persister , lce . Key ) , lce . Collection ) ;
52
+ }
53
+
54
+ if ( log . IsDebugEnabled )
55
+ {
56
+ log . Debug ( "removing collection load entry [" + lce + "]" ) ;
57
+ }
58
+
59
+ // todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
60
+ loadContexts . UnregisterLoadingCollectionXRef ( collectionKey ) ;
61
+ toRemove . Add ( collectionKey ) ;
62
+ }
63
+ }
64
+
65
+ localLoadingCollectionKeys . ExceptWith ( toRemove ) ;
66
+ await ( EndLoadingCollectionsAsync ( persister , matches ) ) ;
67
+ if ( ( localLoadingCollectionKeys . Count == 0 ) )
68
+ {
69
+ // todo : hack!!!
70
+ // NOTE : here we cleanup the load context when we have no more local
71
+ // LCE entries. This "works" for the time being because really
72
+ // only the collection load contexts are implemented. Long term,
73
+ // this cleanup should become part of the "close result set"
74
+ // processing from the (sandbox/jdbc) jdbc-container code.
75
+ loadContexts . Cleanup ( resultSet ) ;
76
+ }
77
+ }
78
+
79
+ private async Task EndLoadingCollectionsAsync ( ICollectionPersister persister , IList < LoadingCollectionEntry > matchedCollectionEntries )
80
+ {
81
+ if ( matchedCollectionEntries == null || matchedCollectionEntries . Count == 0 )
82
+ {
83
+ if ( log . IsDebugEnabled )
84
+ {
85
+ log . Debug ( "no collections were found in result set for role: " + persister . Role ) ;
86
+ }
87
+
88
+ return ;
89
+ }
90
+
91
+ int count = matchedCollectionEntries . Count ;
92
+ if ( log . IsDebugEnabled )
93
+ {
94
+ log . Debug ( count + " collections were found in result set for role: " + persister . Role ) ;
95
+ }
96
+
97
+ for ( int i = 0 ; i < count ; i ++ )
98
+ {
99
+ await ( EndLoadingCollectionAsync ( matchedCollectionEntries [ i ] , persister ) ) ;
100
+ }
101
+
102
+ if ( log . IsDebugEnabled )
103
+ {
104
+ log . Debug ( count + " collections initialized for role: " + persister . Role ) ;
105
+ }
106
+ }
107
+
108
+ private async Task EndLoadingCollectionAsync ( LoadingCollectionEntry lce , ICollectionPersister persister )
109
+ {
110
+ if ( log . IsDebugEnabled )
111
+ {
112
+ log . Debug ( "ending loading collection [" + lce + "]" ) ;
113
+ }
114
+
115
+ ISessionImplementor session = LoadContext . PersistenceContext . Session ;
116
+ bool statsEnabled = session . Factory . Statistics . IsStatisticsEnabled ;
117
+ var stopWath = new Stopwatch ( ) ;
118
+ if ( statsEnabled )
119
+ {
120
+ stopWath . Start ( ) ;
121
+ }
122
+
123
+ bool hasNoQueuedAdds = lce . Collection . EndRead ( persister ) ; // warning: can cause a recursive calls! (proxy initialization)
124
+ if ( persister . CollectionType . HasHolder ( ) )
125
+ {
126
+ LoadContext . PersistenceContext . AddCollectionHolder ( lce . Collection ) ;
127
+ }
128
+
129
+ CollectionEntry ce = LoadContext . PersistenceContext . GetCollectionEntry ( lce . Collection ) ;
130
+ if ( ce == null )
131
+ {
132
+ ce = LoadContext . PersistenceContext . AddInitializedCollection ( persister , lce . Collection , lce . Key ) ;
133
+ }
134
+ else
135
+ {
136
+ ce . PostInitialize ( lce . Collection ) ;
137
+ }
138
+
139
+ bool addToCache = hasNoQueuedAdds && persister . HasCache && ( ( session . CacheMode & CacheMode . Put ) == CacheMode . Put ) && ! ce . IsDoremove ; // and this is not a forced initialization during flush
140
+ if ( addToCache )
141
+ {
142
+ await ( AddCollectionToCacheAsync ( lce , persister ) ) ;
143
+ }
144
+
145
+ if ( log . IsDebugEnabled )
146
+ {
147
+ log . Debug ( "collection fully initialized: " + MessageHelper . CollectionInfoString ( persister , lce . Collection , lce . Key , session ) ) ;
148
+ }
149
+
150
+ if ( statsEnabled )
151
+ {
152
+ stopWath . Stop ( ) ;
153
+ session . Factory . StatisticsImplementor . LoadCollection ( persister . Role , stopWath . Elapsed ) ;
154
+ }
155
+ }
156
+
157
+ /// <summary> Add the collection to the second-level cache </summary>
158
+ /// <param name = "lce">The entry representing the collection to add </param>
159
+ /// <param name = "persister">The persister </param>
160
+ private async Task AddCollectionToCacheAsync ( LoadingCollectionEntry lce , ICollectionPersister persister )
161
+ {
162
+ ISessionImplementor session = LoadContext . PersistenceContext . Session ;
163
+ ISessionFactoryImplementor factory = session . Factory ;
164
+ if ( log . IsDebugEnabled )
165
+ {
166
+ log . Debug ( "Caching collection: " + MessageHelper . CollectionInfoString ( persister , lce . Collection , lce . Key , session ) ) ;
167
+ }
168
+
169
+ if ( ! ( session . EnabledFilters . Count == 0 ) && persister . IsAffectedByEnabledFilters ( session ) )
170
+ {
171
+ // some filters affecting the collection are enabled on the session, so do not do the put into the cache.
172
+ log . Debug ( "Refusing to add to cache due to enabled filters" ) ;
173
+ // todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
174
+ // but CacheKey is currently used for both collections and entities; would ideally need to define two separate ones;
175
+ // currently this works in conjunction with the check on
176
+ // DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
177
+ // cache with enabled filters).
178
+ return ; // EARLY EXIT!!!!!
179
+ }
180
+
181
+ IComparer versionComparator ;
182
+ object version ;
183
+ if ( persister . IsVersioned )
184
+ {
185
+ versionComparator = persister . OwnerEntityPersister . VersionType . Comparator ;
186
+ object collectionOwner = LoadContext . PersistenceContext . GetCollectionOwner ( lce . Key , persister ) ;
187
+ version = LoadContext . PersistenceContext . GetEntry ( collectionOwner ) . Version ;
188
+ }
189
+ else
190
+ {
191
+ version = null ;
192
+ versionComparator = null ;
193
+ }
194
+
195
+ CollectionCacheEntry entry = await ( CollectionCacheEntry . CreateAsync ( lce . Collection , persister ) ) ;
196
+ CacheKey cacheKey = session . GenerateCacheKey ( lce . Key , persister . KeyType , persister . Role ) ;
197
+ bool put = persister . Cache . Put ( cacheKey , persister . CacheEntryStructure . Structure ( entry ) , session . Timestamp , version , versionComparator , factory . Settings . IsMinimalPutsEnabled && session . CacheMode != CacheMode . Refresh ) ;
198
+ if ( put && factory . Statistics . IsStatisticsEnabled )
199
+ {
200
+ factory . StatisticsImplementor . SecondLevelCachePut ( persister . Cache . RegionName ) ;
201
+ }
202
+ }
203
+ }
204
+ }
0 commit comments