use of org.hibernate.engine.spi.CollectionKey in project hibernate-orm by hibernate.
the class CollectionLoadContext method getLoadingCollection.
/**
* Retrieve the collection that is being loaded as part of processing this
* result set.
* <p/>
* Basically, there are two valid return values from this method:<ul>
* <li>an instance of {@link org.hibernate.collection.spi.PersistentCollection} which indicates to
* continue loading the result set row data into that returned collection
* instance; this may be either an instance already associated and in the
* midst of being loaded, or a newly instantiated instance as a matching
* associated collection was not found.</li>
* <li><i>null</i> indicates to ignore the corresponding result set row
* data relating to the requested collection; this indicates that either
* the collection was found to already be associated with the persistence
* context in a fully loaded state, or it was found in a loading state
* associated with another result set processing context.</li>
* </ul>
*
* @param persister The persister for the collection being requested.
* @param key The key of the collection being requested.
*
* @return The loading collection (see discussion above).
*/
public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
final EntityMode em = persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode();
final CollectionKey collectionKey = new CollectionKey(persister, key, em);
if (LOG.isTraceEnabled()) {
LOG.tracev("Starting attempt to find loading collection [{0}]", MessageHelper.collectionInfoString(persister.getRole(), key));
}
final LoadingCollectionEntry loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry(collectionKey);
if (loadingCollectionEntry == null) {
// look for existing collection as part of the persistence context
PersistentCollection collection = loadContexts.getPersistenceContext().getCollection(collectionKey);
if (collection != null) {
if (collection.wasInitialized()) {
LOG.trace("Collection already initialized; ignoring");
// ignore this row of results! Note the early exit
return null;
}
LOG.trace("Collection not yet initialized; initializing");
} else {
final Object owner = loadContexts.getPersistenceContext().getCollectionOwner(key, persister);
final boolean newlySavedEntity = owner != null && loadContexts.getPersistenceContext().getEntry(owner).getStatus() != Status.LOADING;
if (newlySavedEntity) {
// important, to account for newly saved entities in query
// todo : some kind of check for new status...
LOG.trace("Owning entity already loaded; ignoring");
return null;
}
// create one
LOG.tracev("Instantiating new collection [key={0}, rs={1}]", key, resultSet);
collection = persister.getCollectionType().instantiate(loadContexts.getPersistenceContext().getSession(), persister, key);
}
collection.beforeInitialize(persister, -1);
collection.beginRead();
localLoadingCollectionKeys.add(collectionKey);
loadContexts.registerLoadingCollectionXRef(collectionKey, new LoadingCollectionEntry(resultSet, persister, key, collection));
return collection;
}
if (loadingCollectionEntry.getResultSet() == resultSet) {
LOG.trace("Found loading collection bound to current result set processing; reading row");
return loadingCollectionEntry.getCollection();
}
// ignore this row, the collection is in process of
// being loaded somewhere further "up" the stack
LOG.trace("Collection is already being initialized; ignoring row");
return null;
}
use of org.hibernate.engine.spi.CollectionKey in project hibernate-orm by hibernate.
the class AbstractFlushingEventListener method postFlush.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Post-flushing section
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* 1. Recreate the collection key -> collection map
* 2. rebuild the collection entries
* 3. call Interceptor.postFlush()
*/
protected void postFlush(SessionImplementor session) throws HibernateException {
LOG.trace("Post flush");
final PersistenceContext persistenceContext = session.getPersistenceContext();
persistenceContext.getCollectionsByKey().clear();
// the database has changed now, so the subselect results need to be invalidated
// the batch fetching queues should also be cleared - especially the collection batch fetching one
persistenceContext.getBatchFetchQueue().clear();
for (Map.Entry<PersistentCollection, CollectionEntry> me : IdentityMap.concurrentEntries(persistenceContext.getCollectionEntries())) {
CollectionEntry collectionEntry = me.getValue();
PersistentCollection persistentCollection = me.getKey();
collectionEntry.postFlush(persistentCollection);
if (collectionEntry.getLoadedPersister() == null) {
//if the collection is dereferenced, unset its session reference and remove from the session cache
//iter.remove(); //does not work, since the entrySet is not backed by the set
persistentCollection.unsetSession(session);
persistenceContext.getCollectionEntries().remove(persistentCollection);
} else {
//otherwise recreate the mapping between the collection and its key
CollectionKey collectionKey = new CollectionKey(collectionEntry.getLoadedPersister(), collectionEntry.getLoadedKey());
persistenceContext.getCollectionsByKey().put(collectionKey, persistentCollection);
}
}
}
use of org.hibernate.engine.spi.CollectionKey in project hibernate-orm by hibernate.
the class CollectionLoadContext method endLoadingCollections.
/**
* Finish the process of collection-loading for this bound result set. Mainly this
* involves cleaning up resources and notifying the collections that loading is
* complete.
*
* @param persister The persister for which to complete loading.
*/
public void endLoadingCollections(CollectionPersister persister) {
final SharedSessionContractImplementor session = getLoadContext().getPersistenceContext().getSession();
if (!loadContexts.hasLoadingCollectionEntries() && localLoadingCollectionKeys.isEmpty()) {
return;
}
// in an effort to avoid concurrent-modification-exceptions (from
// potential recursive calls back through here as a result of the
// eventual call to PersistentCollection#endRead), we scan the
// internal loadingCollections map for matches and store those matches
// in a temp collection. the temp collection is then used to "drive"
// the #endRead processing.
List<LoadingCollectionEntry> matches = null;
final Iterator itr = localLoadingCollectionKeys.iterator();
while (itr.hasNext()) {
final CollectionKey collectionKey = (CollectionKey) itr.next();
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry(collectionKey);
if (lce == null) {
LOG.loadingCollectionKeyNotFound(collectionKey);
} else if (lce.getResultSet() == resultSet && lce.getPersister() == persister) {
if (matches == null) {
matches = new ArrayList<>();
}
matches.add(lce);
if (lce.getCollection().getOwner() == null) {
session.getPersistenceContext().addUnownedCollection(new CollectionKey(persister, lce.getKey(), persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode()), lce.getCollection());
}
LOG.tracev("Removing collection load entry [{0}]", lce);
// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
loadContexts.unregisterLoadingCollectionXRef(collectionKey);
itr.remove();
}
}
endLoadingCollections(persister, matches);
if (localLoadingCollectionKeys.isEmpty()) {
// todo : hack!!!
// NOTE : here we cleanup the load context when we have no more local
// LCE entries. This "works" for the time being because really
// only the collection load contexts are implemented. Long term,
// this cleanup should become part of the "close result set"
// processing from the (sandbox/jdbc) jdbc-container code.
loadContexts.cleanup(resultSet);
}
}
use of org.hibernate.engine.spi.CollectionKey in project hibernate-orm by hibernate.
the class AbstractEntityPersister method initializeLazyProperty.
public Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session) {
final EntityEntry entry = session.getPersistenceContext().getEntry(entity);
final InterceptorImplementor interceptor = ((PersistentAttributeInterceptable) entity).$$_hibernate_getInterceptor();
assert interceptor != null : "Expecting bytecode interceptor to be non-null";
if (hasCollections()) {
final Type type = getPropertyType(fieldName);
if (type.isCollectionType()) {
// we have a condition where a collection attribute is being access via enhancement:
// we can circumvent all the rest and just return the PersistentCollection
final CollectionType collectionType = (CollectionType) type;
final CollectionPersister persister = factory.getMetamodel().collectionPersister(collectionType.getRole());
// Get/create the collection, and make sure it is initialized! This initialized part is
// different from proxy-based scenarios where we have to create the PersistentCollection
// reference "ahead of time" to add as a reference to the proxy. For bytecode solutions
// we are not creating the PersistentCollection ahead of time, but instead we are creating
// it on first request through the enhanced entity.
// see if there is already a collection instance associated with the session
// NOTE : can this ever happen?
final Serializable key = getCollectionKey(persister, entity, entry, session);
PersistentCollection collection = session.getPersistenceContext().getCollection(new CollectionKey(persister, key));
if (collection == null) {
collection = collectionType.instantiate(session, persister, key);
collection.setOwner(entity);
session.getPersistenceContext().addUninitializedCollection(persister, collection, key);
}
// HHH-11161 Initialize, if the collection is not extra lazy
if (!persister.isExtraLazy()) {
session.initializeCollection(collection, false);
}
interceptor.attributeInitialized(fieldName);
if (collectionType.isArrayType()) {
session.getPersistenceContext().addCollectionHolder(collection);
}
// update the "state" of the entity's EntityEntry to over-write UNFETCHED_PROPERTY reference
// for the collection to the just loaded collection
final EntityEntry ownerEntry = session.getPersistenceContext().getEntry(entity);
if (ownerEntry == null) {
// not good
throw new AssertionFailure("Could not locate EntityEntry for the collection owner in the PersistenceContext");
}
ownerEntry.overwriteLoadedStateCollectionValue(fieldName, collection);
// EARLY EXIT!!!
return collection;
}
}
final Serializable id = session.getContextEntityIdentifier(entity);
if (entry == null) {
throw new HibernateException("entity is not associated with the session: " + id);
}
if (LOG.isTraceEnabled()) {
LOG.tracev("Initializing lazy properties of: {0}, field access: {1}", MessageHelper.infoString(this, id, getFactory()), fieldName);
}
if (session.getCacheMode().isGetEnabled() && hasCache() && isLazyPropertiesCacheable()) {
final EntityRegionAccessStrategy cache = getCacheAccessStrategy();
final Object cacheKey = cache.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier());
final Object ce = CacheHelper.fromSharedCache(session, cacheKey, cache);
if (ce != null) {
final CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure(ce, factory);
final Object initializedValue = initializeLazyPropertiesFromCache(fieldName, entity, session, entry, cacheEntry);
interceptor.attributeInitialized(fieldName);
// NOTE EARLY EXIT!!!
return initializedValue;
}
}
return initializeLazyPropertiesFromDatastore(fieldName, entity, session, id, entry);
}
use of org.hibernate.engine.spi.CollectionKey in project hibernate-orm by hibernate.
the class CollectionType method getCollection.
/**
* instantiate a collection wrapper (called when loading an object)
*
* @param key The collection owner key
* @param session The session from which the request is originating.
* @param owner The collection owner
* @return The collection
*/
public Object getCollection(Serializable key, SharedSessionContractImplementor session, Object owner) {
CollectionPersister persister = getPersister(session);
final PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityMode entityMode = persister.getOwnerEntityPersister().getEntityMode();
// check if collection is currently being loaded
PersistentCollection collection = persistenceContext.getLoadContexts().locateLoadingCollection(persister, key);
if (collection == null) {
// check if it is already completely loaded, but unowned
collection = persistenceContext.useUnownedCollection(new CollectionKey(persister, key, entityMode));
if (collection == null) {
collection = persistenceContext.getCollection(new CollectionKey(persister, key, entityMode));
if (collection == null) {
// create a new collection wrapper, to be initialized later
collection = instantiate(session, persister, key);
collection.setOwner(owner);
persistenceContext.addUninitializedCollection(persister, collection, key);
// some collections are not lazy:
if (initializeImmediately()) {
session.initializeCollection(collection, false);
} else if (!persister.isLazy()) {
persistenceContext.addNonLazyCollection(collection);
}
if (hasHolder()) {
session.getPersistenceContext().addCollectionHolder(collection);
}
}
}
if (LOG.isTraceEnabled()) {
LOG.tracef("Created collection wrapper: %s", MessageHelper.collectionInfoString(persister, collection, key, session));
}
}
collection.setOwner(owner);
return collection.getValue();
}
Aggregations