6
6
7
7
8
8
import org .hibernate .CacheMode ;
9
- import org .hibernate .cache . spi . access . CollectionDataAccess ;
9
+ import org .hibernate .SharedSessionContract ;
10
10
import org .hibernate .cache .spi .entry .CollectionCacheEntry ;
11
11
import org .hibernate .collection .spi .PersistentCollection ;
12
- import org .hibernate .engine .spi .BatchFetchQueue ;
13
12
import org .hibernate .engine .spi .CollectionEntry ;
14
- import org .hibernate .engine .spi .EntityEntry ;
15
13
import org .hibernate .engine .spi .PersistenceContext ;
16
- import org .hibernate .engine .spi .SessionEventListenerManager ;
17
14
import org .hibernate .engine .spi .SessionFactoryImplementor ;
18
15
import org .hibernate .engine .spi .SharedSessionContractImplementor ;
19
16
import org .hibernate .event .monitor .spi .EventMonitor ;
20
- import org .hibernate .event .monitor .spi .DiagnosticEvent ;
21
17
import org .hibernate .internal .CoreLogging ;
22
18
import org .hibernate .internal .CoreMessageLogger ;
23
- import org .hibernate .metamodel .mapping .PluralAttributeMapping ;
24
19
import org .hibernate .persister .collection .CollectionPersister ;
25
- import org .hibernate .persister .entity .EntityPersister ;
26
20
import org .hibernate .sql .results .jdbc .spi .JdbcValues ;
27
21
import org .hibernate .sql .results .jdbc .spi .JdbcValuesMapping ;
28
- import org .hibernate .sql .results .jdbc .spi .JdbcValuesMappingResolution ;
29
22
import org .hibernate .sql .results .spi .RowReader ;
30
23
import org .hibernate .sql .results .spi .RowTransformer ;
31
- import org .hibernate .stat .spi .StatisticsImplementor ;
32
- import org .hibernate .type .EntityType ;
33
24
34
25
import static org .hibernate .pretty .MessageHelper .collectionInfoString ;
35
26
@@ -53,9 +44,8 @@ public static <R> RowReader<R> createRowReader(
53
44
RowTransformer <R > rowTransformer ,
54
45
Class <R > transformedResultJavaType ,
55
46
JdbcValuesMapping jdbcValuesMapping ) {
56
- final JdbcValuesMappingResolution jdbcValuesMappingResolution = jdbcValuesMapping .resolveAssemblers ( sessionFactory );
57
47
return new StandardRowReader <>(
58
- jdbcValuesMappingResolution ,
48
+ jdbcValuesMapping . resolveAssemblers ( sessionFactory ) ,
59
49
rowTransformer ,
60
50
transformedResultJavaType
61
51
);
@@ -64,81 +54,95 @@ public static <R> RowReader<R> createRowReader(
64
54
public static void finalizeCollectionLoading (
65
55
PersistenceContext persistenceContext ,
66
56
CollectionPersister collectionDescriptor ,
67
- PersistentCollection <?> collectionInstance ,
57
+ PersistentCollection <?> collection ,
68
58
Object key ,
69
59
boolean hasNoQueuedAdds ) {
70
- final SharedSessionContractImplementor session = persistenceContext .getSession ();
71
-
72
- CollectionEntry collectionEntry = persistenceContext .getCollectionEntry ( collectionInstance );
73
- if ( collectionEntry == null ) {
74
- collectionEntry = persistenceContext .addInitializedCollection ( collectionDescriptor , collectionInstance , key );
75
- }
76
- else {
77
- collectionEntry .postInitialize ( collectionInstance , session );
78
- }
79
-
60
+ final var session = persistenceContext .getSession ();
61
+ final var collectionEntry =
62
+ initializedEntry ( persistenceContext , collectionDescriptor , collection , key , session );
80
63
if ( collectionDescriptor .getCollectionType ().hasHolder () ) {
81
- // in case of PersistentArrayHolder we have to realign
82
- // the EntityEntry loaded state with the entity values
83
- final Object owner = collectionInstance .getOwner ();
84
- final EntityEntry entry = persistenceContext .getEntry ( owner );
85
- final Object [] loadedState = entry .getLoadedState ();
86
- if ( loadedState != null ) {
87
- final PluralAttributeMapping mapping = collectionDescriptor .getAttributeMapping ();
88
- final int propertyIndex = mapping .getStateArrayPosition ();
89
- loadedState [propertyIndex ] = mapping .getValue ( owner );
90
- }
91
- // else it must be an immutable entity or loaded in read-only mode,
92
- // but unfortunately we have no way to reliably determine that here
93
- persistenceContext .addCollectionHolder ( collectionInstance );
64
+ addCollectionHolder ( persistenceContext , collectionDescriptor , collection );
94
65
}
95
-
96
- final BatchFetchQueue batchFetchQueue = persistenceContext .getBatchFetchQueue ();
97
- batchFetchQueue .removeBatchLoadableCollection ( collectionEntry );
98
-
99
- // add to cache if:
100
- final boolean addToCache =
101
- // there were no queued additions
102
- hasNoQueuedAdds
103
- // and the role has a cache
104
- && collectionDescriptor .hasCache ()
105
- // and this is not a forced initialization during flush
106
- && session .getCacheMode ().isPutEnabled () && !collectionEntry .isDoremove ();
107
- if ( addToCache ) {
108
- addCollectionToCache ( persistenceContext , collectionDescriptor , collectionInstance , key );
66
+ persistenceContext .getBatchFetchQueue ().removeBatchLoadableCollection ( collectionEntry );
67
+ if ( addToCache ( session , collectionEntry , collectionDescriptor , hasNoQueuedAdds ) ) {
68
+ addCollectionToCache ( persistenceContext , collectionDescriptor , collection , key );
69
+ }
70
+ final var statistics = session .getFactory ().getStatistics ();
71
+ if ( statistics .isStatisticsEnabled () ) {
72
+ statistics .loadCollection ( collectionDescriptor .getRole () );
109
73
}
110
74
111
75
if ( LOG .isTraceEnabled () ) {
112
76
LOG .trace ( "Collection fully initialized: "
113
- + collectionInfoString ( collectionDescriptor , collectionInstance , key , session ) );
114
- }
115
-
116
- final StatisticsImplementor statistics = session .getFactory ().getStatistics ();
117
- if ( statistics .isStatisticsEnabled () ) {
118
- statistics .loadCollection ( collectionDescriptor .getRole () );
77
+ + collectionInfoString ( collectionDescriptor , collection , key , session ) );
119
78
}
120
79
121
80
// todo (6.0) : there is other logic still needing to be implemented here. caching, etc
122
81
// see org.hibernate.engine.loading.internal.CollectionLoadContext#endLoadingCollection in 5.x
123
82
}
124
83
84
+ private static boolean addToCache (
85
+ SharedSessionContract session ,
86
+ CollectionEntry collectionEntry ,
87
+ CollectionPersister collectionDescriptor ,
88
+ boolean hasNoQueuedAdds ) {
89
+ return hasNoQueuedAdds // there were no queued additions
90
+ && collectionDescriptor .hasCache () // the collection role has a cache
91
+ && session .getCacheMode ().isPutEnabled () // the session cache mode allows puts
92
+ && !collectionEntry .isDoremove (); // this is not a forced initialization during flush
93
+ }
94
+
95
+ private static void addCollectionHolder (
96
+ PersistenceContext persistenceContext ,
97
+ CollectionPersister collectionDescriptor ,
98
+ PersistentCollection <?> collectionInstance ) {
99
+ // in case of PersistentArrayHolder we have to realign
100
+ // the EntityEntry loaded state with the entity values
101
+ final Object owner = collectionInstance .getOwner ();
102
+ final var loadedState = persistenceContext .getEntry ( owner ).getLoadedState ();
103
+ if ( loadedState != null ) {
104
+ final var mapping = collectionDescriptor .getAttributeMapping ();
105
+ final int propertyIndex = mapping .getStateArrayPosition ();
106
+ loadedState [propertyIndex ] = mapping .getValue ( owner );
107
+ }
108
+ // else it must be an immutable entity or loaded in read-only mode,
109
+ // but, unfortunately, we have no way to reliably determine that here
110
+ persistenceContext .addCollectionHolder ( collectionInstance );
111
+ }
112
+
113
+ private static CollectionEntry initializedEntry (
114
+ PersistenceContext context ,
115
+ CollectionPersister collectionDescriptor ,
116
+ PersistentCollection <?> collectionInstance ,
117
+ Object key ,
118
+ SharedSessionContractImplementor session ) {
119
+ final var collectionEntry = context .getCollectionEntry ( collectionInstance );
120
+ if ( collectionEntry == null ) {
121
+ return context .addInitializedCollection ( collectionDescriptor , collectionInstance , key );
122
+ }
123
+ else {
124
+ collectionEntry .postInitialize ( collectionInstance , session );
125
+ return collectionEntry ;
126
+ }
127
+ }
128
+
125
129
/**
126
130
* Add the collection to the second-level cache
127
131
*/
128
132
private static void addCollectionToCache (
129
133
PersistenceContext persistenceContext ,
130
134
CollectionPersister collectionDescriptor ,
131
- PersistentCollection <?> collectionInstance ,
135
+ PersistentCollection <?> collection ,
132
136
Object key ) {
133
- final SharedSessionContractImplementor session = persistenceContext .getSession ();
134
- final SessionFactoryImplementor factory = session .getFactory ();
137
+ final var session = persistenceContext .getSession ();
135
138
136
139
if ( LOG .isTraceEnabled () ) {
137
140
LOG .trace ( "Caching collection: "
138
- + collectionInfoString ( collectionDescriptor , collectionInstance , key , session ) );
141
+ + collectionInfoString ( collectionDescriptor , collection , key , session ) );
139
142
}
140
143
141
- if ( session .getLoadQueryInfluencers ().hasEnabledFilters () && collectionDescriptor .isAffectedByEnabledFilters ( session ) ) {
144
+ if ( session .getLoadQueryInfluencers ().hasEnabledFilters ()
145
+ && collectionDescriptor .isAffectedByEnabledFilters ( session ) ) {
142
146
// some filters affecting the collection are enabled on the session, so do not do the put into the cache.
143
147
LOG .debug ( "Refusing to add to cache due to enabled filters" );
144
148
// todo : add the notion of enabled filters to the cache key to differentiate filtered collections from non-filtered;
@@ -150,56 +154,43 @@ private static void addCollectionToCache(
150
154
151
155
final Object version ;
152
156
if ( collectionDescriptor .isVersioned () ) {
153
- Object collectionOwner = persistenceContext .getCollectionOwner ( key , collectionDescriptor );
157
+ final Object collectionOwner =
158
+ getCollectionOwner ( persistenceContext , collectionDescriptor , collection , key , session );
154
159
if ( collectionOwner == null ) {
155
- // generally speaking this would be caused by the collection key being defined by a property-ref, thus
156
- // the collection key and the owner key would not match up. In this case, try to use the key of the
157
- // owner instance associated with the collection itself, if one. If the collection does already know
158
- // about its owner, that owner should be the same instance as associated with the PC, but we do the
159
- // resolution against the PC anyway just to be safe since the lookup should not be costly.
160
- if ( collectionInstance != null ) {
161
- final Object linkedOwner = collectionInstance .getOwner ();
162
- if ( linkedOwner != null ) {
163
- final Object ownerKey = collectionDescriptor .getOwnerEntityPersister ().getIdentifier ( linkedOwner , session );
164
- collectionOwner = persistenceContext .getCollectionOwner ( ownerKey , collectionDescriptor );
165
- }
166
- }
167
- if ( collectionOwner == null ) {
168
- LOG .debugf ( "Unable to resolve owner of loading collection for second level caching. Refusing to add to cache." );
169
- return ;
170
- }
160
+ LOG .debug ( "Unable to resolve owner of loading collection for second level caching. Refusing to add to cache." );
161
+ return ;
171
162
}
172
163
version = persistenceContext .getEntry ( collectionOwner ).getVersion ();
173
164
}
174
165
else {
175
166
version = null ;
176
167
}
177
168
178
- final CollectionCacheEntry entry = new CollectionCacheEntry ( collectionInstance , collectionDescriptor );
179
- final CollectionDataAccess cacheAccess = collectionDescriptor .getCacheAccessStrategy ();
169
+ addCollectionToCache ( persistenceContext , collectionDescriptor , collection , key , version );
170
+ }
171
+
172
+ private static void addCollectionToCache (
173
+ PersistenceContext context ,
174
+ CollectionPersister collectionDescriptor ,
175
+ PersistentCollection <?> collection ,
176
+ Object key ,
177
+ Object version ) {
178
+ final var session = context .getSession ();
179
+ final var factory = session .getFactory ();
180
+ final var entry = new CollectionCacheEntry ( collection , collectionDescriptor );
181
+ final var cacheAccess = collectionDescriptor .getCacheAccessStrategy ();
180
182
final Object cacheKey = cacheAccess .generateCacheKey (
181
183
key ,
182
184
collectionDescriptor ,
183
185
session .getFactory (),
184
186
session .getTenantIdentifier ()
185
187
);
186
188
187
- boolean isPutFromLoad = true ;
188
- if ( collectionDescriptor .getElementType () instanceof EntityType ) {
189
- final EntityPersister entityPersister = collectionDescriptor .getElementPersister ();
190
- for ( Object id : entry .getState () ) {
191
- if ( persistenceContext .wasInsertedDuringTransaction ( entityPersister , id ) ) {
192
- isPutFromLoad = false ;
193
- break ;
194
- }
195
- }
196
- }
197
-
198
189
// CollectionRegionAccessStrategy has no update, so avoid putting uncommitted data via putFromLoad
199
- if ( isPutFromLoad ) {
200
- final SessionEventListenerManager eventListenerManager = session .getEventListenerManager ();
201
- final EventMonitor eventMonitor = session .getEventMonitor ();
202
- final DiagnosticEvent cachePutEvent = eventMonitor .beginCachePutEvent ();
190
+ if ( isPutFromLoad ( context , collectionDescriptor , entry ) ) {
191
+ final var eventListenerManager = session .getEventListenerManager ();
192
+ final var eventMonitor = session .getEventMonitor ();
193
+ final var cachePutEvent = eventMonitor .beginCachePutEvent ();
203
194
boolean put = false ;
204
195
try {
205
196
eventListenerManager .cachePutStart ();
@@ -209,7 +200,7 @@ private static void addCollectionToCache(
209
200
collectionDescriptor .getCacheEntryStructure ().structure ( entry ),
210
201
version ,
211
202
factory .getSessionFactoryOptions ().isMinimalPutsEnabled ()
212
- && session .getCacheMode ()!= CacheMode .REFRESH
203
+ && session .getCacheMode () != CacheMode .REFRESH
213
204
);
214
205
}
215
206
finally {
@@ -223,15 +214,58 @@ private static void addCollectionToCache(
223
214
);
224
215
eventListenerManager .cachePutEnd ();
225
216
226
- final StatisticsImplementor statistics = factory .getStatistics ();
217
+ final var statistics = factory .getStatistics ();
227
218
if ( put && statistics .isStatisticsEnabled () ) {
228
219
statistics .collectionCachePut (
229
220
collectionDescriptor .getNavigableRole (),
230
- collectionDescriptor . getCacheAccessStrategy () .getRegion ().getName ()
221
+ cacheAccess .getRegion ().getName ()
231
222
);
232
223
}
224
+ }
225
+ }
226
+ }
227
+
228
+ private static boolean isPutFromLoad (
229
+ PersistenceContext context ,
230
+ CollectionPersister collectionDescriptor ,
231
+ CollectionCacheEntry entry ) {
232
+ if ( collectionDescriptor .getElementType ().isEntityType () ) {
233
+ final var entityPersister = collectionDescriptor .getElementPersister ();
234
+ for ( Object id : entry .getState () ) {
235
+ if ( context .wasInsertedDuringTransaction ( entityPersister , id ) ) {
236
+ return false ;
237
+ }
238
+ }
239
+ }
240
+ return true ;
241
+ }
233
242
243
+ private static Object getCollectionOwner (
244
+ PersistenceContext context ,
245
+ CollectionPersister collectionDescriptor ,
246
+ PersistentCollection <?> collection ,
247
+ Object key ,
248
+ SharedSessionContractImplementor session ) {
249
+ final Object collectionOwner = context .getCollectionOwner ( key , collectionDescriptor );
250
+ if ( collectionOwner == null ) {
251
+ // This happens when the collection key is defined by a property-ref. In this case, the collection key
252
+ // and the owner key would not match up. Use the key of the owner instance associated with the collection
253
+ // itself, if there is one. If the collection does already know about its owner, that owner should be the
254
+ // same instance as associated with the PC, but we do the resolution against the PC anyway just to be safe,
255
+ // since the lookup should not be costly.
256
+ if ( collection != null ) {
257
+ final Object linkedOwner = collection .getOwner ();
258
+ if ( linkedOwner != null ) {
259
+ final Object ownerKey =
260
+ collectionDescriptor .getOwnerEntityPersister ()
261
+ .getIdentifier ( linkedOwner , session );
262
+ return context .getCollectionOwner ( ownerKey , collectionDescriptor );
263
+ }
234
264
}
265
+ return null ;
266
+ }
267
+ else {
268
+ return collectionOwner ;
235
269
}
236
270
}
237
271
}
0 commit comments