📄 loader.java
字号:
//for sets, we should end the collection load after resolving
//the entities, since we might call hashCode() on the elements
//TODO: or we could do this polymorphically, and have two
// different operations implemented differently for arrays
endCollectionLoad( resultSetId, session, collectionPersisters[i] );
}
}
}
}
private void endCollectionLoad(
final Object resultSetId,
final SessionImplementor session,
final CollectionPersister collectionPersister
) {
//this is a query and we are loading multiple instances of the same collection role
session.getPersistenceContext().getCollectionLoadContext()
.endLoadingCollections( collectionPersister, resultSetId, session );
}
protected List getResultList(List results) throws QueryException {
return results;
}
/**
* Get the actual object that is returned in the user-visible result list.
* This empty implementation merely returns its first argument. This is
* overridden by some subclasses.
*/
protected Object getResultColumnOrRow(Object[] row, ResultSet rs, SessionImplementor session)
throws SQLException, HibernateException {
return row;
}
/**
* For missing objects associated by one-to-one with another object in the
* result set, register the fact that the the object is missing with the
* session.
*/
private void registerNonExists(
final EntityKey[] keys,
final Loadable[] persisters,
final SessionImplementor session) {
final int[] owners = getOwners();
if ( owners != null ) {
EntityType[] ownerAssociationTypes = getOwnerAssociationTypes();
for ( int i = 0; i < keys.length; i++ ) {
int owner = owners[i];
if ( owner > -1 ) {
EntityKey ownerKey = keys[owner];
if ( keys[i] == null && ownerKey != null ) {
final PersistenceContext persistenceContext = session.getPersistenceContext();
/*final boolean isPrimaryKey;
final boolean isSpecialOneToOne;
if ( ownerAssociationTypes == null || ownerAssociationTypes[i] == null ) {
isPrimaryKey = true;
isSpecialOneToOne = false;
}
else {
isPrimaryKey = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName()==null;
isSpecialOneToOne = ownerAssociationTypes[i].getLHSPropertyName()!=null;
}*/
//TODO: can we *always* use the "null property" approach for everything?
/*if ( isPrimaryKey && !isSpecialOneToOne ) {
persistenceContext.addNonExistantEntityKey(
new EntityKey( ownerKey.getIdentifier(), persisters[i], session.getEntityMode() )
);
}
else if ( isSpecialOneToOne ) {*/
boolean isOneToOneAssociation = ownerAssociationTypes!=null &&
ownerAssociationTypes[i]!=null &&
ownerAssociationTypes[i].isOneToOne();
if ( isOneToOneAssociation ) {
persistenceContext.addNullProperty( ownerKey,
ownerAssociationTypes[i].getPropertyName() );
}
/*}
else {
persistenceContext.addNonExistantEntityUniqueKey( new EntityUniqueKey(
persisters[i].getEntityName(),
ownerAssociationTypes[i].getRHSUniqueKeyPropertyName(),
ownerKey.getIdentifier(),
persisters[owner].getIdentifierType(),
session.getEntityMode()
) );
}*/
}
}
}
}
}
/**
* Read one collection element from the current row of the JDBC result set
*/
private void readCollectionElement(
final Object optionalOwner,
final Serializable optionalKey,
final CollectionPersister persister,
final CollectionAliases descriptor,
final ResultSet rs,
final SessionImplementor session)
throws HibernateException, SQLException {
final PersistenceContext persistenceContext = session.getPersistenceContext();
final Serializable collectionRowKey = (Serializable) persister.readKey(
rs,
descriptor.getSuffixedKeyAliases(),
session
);
if ( collectionRowKey != null ) {
// we found a collection element in the result set
if ( log.isDebugEnabled() ) {
log.debug(
"found row of collection: " +
MessageHelper.collectionInfoString( persister, collectionRowKey, getFactory() )
);
}
Object owner = optionalOwner;
if ( owner == null ) {
owner = persistenceContext.getCollectionOwner( collectionRowKey, persister );
if ( owner == null ) {
//TODO: This is assertion is disabled because there is a bug that means the
// original owner of a transient, uninitialized collection is not known
// if the collection is re-referenced by a different object associated
// with the current Session
//throw new AssertionFailure("bug loading unowned collection");
}
}
PersistentCollection rowCollection = persistenceContext.getCollectionLoadContext()
.getLoadingCollection( persister, collectionRowKey, rs, session.getEntityMode() );
if ( rowCollection != null ) {
rowCollection.readFrom( rs, persister, descriptor, owner );
}
}
else if ( optionalKey != null ) {
// we did not find a collection element in the result set, so we
// ensure that a collection is created with the owner's identifier,
// since what we have is an empty collection
if ( log.isDebugEnabled() ) {
log.debug(
"result set contains (possibly empty) collection: " +
MessageHelper.collectionInfoString( persister, optionalKey, getFactory() )
);
}
persistenceContext.getCollectionLoadContext()
.getLoadingCollection( persister, optionalKey, rs, session.getEntityMode() ); //handle empty collection
}
// else no collection element, but also no owner
}
/**
* If this is a collection initializer, we need to tell the session that a collection
* is being initilized, to account for the possibility of the collection having
* no elements (hence no rows in the result set).
*/
private void handleEmptyCollections(
final Serializable[] keys,
final Object resultSetId,
final SessionImplementor session) throws HibernateException {
if ( keys != null ) {
// this is a collection initializer, so we must create a collection
// for each of the passed-in keys, to account for the possibility
// that the collection is empty and has no rows in the result set
CollectionPersister[] collectionPersisters = getCollectionPersisters();
for ( int j=0; j<collectionPersisters.length; j++ ) {
for ( int i = 0; i < keys.length; i++ ) {
//handle empty collections
if ( log.isDebugEnabled() ) {
log.debug(
"result set contains (possibly empty) collection: " +
MessageHelper.collectionInfoString( collectionPersisters[j], keys[i], getFactory() )
);
}
session.getPersistenceContext()
.getCollectionLoadContext()
.getLoadingCollection(
collectionPersisters[j],
keys[i],
resultSetId,
session.getEntityMode()
);
}
}
}
// else this is not a collection initializer (and empty collections will
// be detected by looking for the owner's identifier in the result set)
}
/**
* Read a row of <tt>Key</tt>s from the <tt>ResultSet</tt> into the given array.
* Warning: this method is side-effecty.
* <p/>
* If an <tt>id</tt> is given, don't bother going to the <tt>ResultSet</tt>.
*/
private EntityKey getKeyFromResultSet(
final int i,
final Loadable persister,
final Serializable id,
final ResultSet rs,
final SessionImplementor session) throws HibernateException, SQLException {
Serializable resultId;
// if we know there is exactly 1 row, we can skip.
// it would be great if we could _always_ skip this;
// it is a problem for <key-many-to-one>
if ( isSingleRowLoader() && id != null ) {
resultId = id;
}
else {
Type idType = persister.getIdentifierType();
resultId = (Serializable) idType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedKeyAliases(),
session,
null //problematic for <key-many-to-one>!
);
final boolean idIsResultId = id != null &&
resultId != null &&
idType.isEqual( id, resultId, session.getEntityMode(), factory );
if ( idIsResultId ) resultId = id; //use the id passed in
}
return resultId == null ?
null :
new EntityKey( resultId, persister, session.getEntityMode() );
}
/**
* Check the version of the object in the <tt>ResultSet</tt> against
* the object version in the session cache, throwing an exception
* if the version numbers are different
*/
private void checkVersion(
final int i,
final Loadable persister,
final Serializable id,
final Object entity,
final ResultSet rs,
final SessionImplementor session)
throws HibernateException, SQLException {
Object version = session.getPersistenceContext().getEntry( entity ).getVersion();
if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet
VersionType versionType = persister.getVersionType();
Object currentVersion = versionType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedVersionAliases(),
session,
null
);
if ( !versionType.isEqual(version, currentVersion) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor()
.optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), id );
}
}
}
/**
* Resolve any ids for currently loaded objects, duplications within the
* <tt>ResultSet</tt>, etc. Instantiate empty objects to be initialized from the
* <tt>ResultSet</tt>. Return an array of objects (a row of results) and an
* array of booleans (by side-effect) that determine whether the corresponding
* object should be initialized.
*/
private Object[] getRow(
final ResultSet rs,
final Loadable[] persisters,
final EntityKey[] keys,
final Object optionalObject,
final EntityKey optionalObjectKey,
final LockMode[] lockModes,
final List hydratedObjects,
final SessionImplementor session)
throws HibernateException, SQLException {
final int cols = persisters.length;
final EntityAliases[] descriptors = getEntityAliases();
if ( log.isDebugEnabled() ) {
log.debug(
"result row: " +
StringHelper.toString( keys )
);
}
final Object[] rowResults = new Object[cols];
for ( int i = 0; i < cols; i++ ) {
Object object = null;
EntityKey key = keys[i];
if ( keys[i] == null ) {
//do nothing
}
else {
//If the object is already loaded, return the loaded one
object = session.getEntityUsingInterceptor( key );
if ( object != null ) {
//its already loaded so don't need to hydrate it
instanceAlreadyLoaded(
rs,
i,
persisters[i],
key,
object,
lockModes[i],
session
);
}
else {
object = instanceNotYetLoaded(
rs,
i,
persisters[i],
descriptors[i].getRowIdAlias(),
key,
lockModes[i],
optionalObjectKey,
optionalObject,
hydratedObjects,
session
);
}
}
rowResults[i] = object;
}
return rowResults;
}
/**
* The entity instance is already in the session cache
*/
private void instanceAlreadyLoaded(
final ResultSet rs,
final int i,
final Loadable persister,
final EntityKey key,
final Object object,
final LockMode lockMode,
final SessionImplementor session)
throws HibernateException, SQLException {
if ( !persister.isInstance( object, session.getEntityMode() ) ) {
throw new WrongClassException(
"loaded object was of wrong class",
key.getIdentifier(),
persister.getEntityName()
);
}
if ( LockMode.NONE != lockMode && upgradeLocks() ) { //no point doing this if NONE was requested
final boolean isVersionCheckNeeded = persister.isVersioned() &&
session.getPersistenceContext().getEntry(object)
.getLockMode().lessThan( lockMode );
// we don't need to worry about existing version being uninitialized
// because this block isn't called by a re-entrant load (re-entrant
// loads _always_ have lock mode NONE)
if (isVersionCheckNeeded) {
//we only check the version when _upgrading_ lock modes
checkVersion( i, persister, key.getIdentifier(), object, rs, session );
//we need to upgrade the lock mode to the mode requested
session.getPersistenceContext().getEntry(object)
.setLockMode(lockMode);
}
}
}
/**
* The entity instance is not in the session cache
*/
private Object instanceNotYetLoaded(
final ResultSet rs,
final int i,
final Loadable persister,
final String rowIdAlias,
final EntityKey key,
final LockMode lockMode,
final EntityKey optionalObjectKey,
final Object optionalObject,
final List hydratedObjects,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -