From: <hib...@li...> - 2006-06-15 16:38:21
|
Author: ste...@jb... Date: 2006-06-15 12:38:03 -0400 (Thu, 15 Jun 2006) New Revision: 10020 Modified: trunk/Hibernate3/src/org/hibernate/type/ManyToOneType.java Log: HHH-1831 : be careful about ManyToOneType adding entity keys to the batch fetch queue Modified: trunk/Hibernate3/src/org/hibernate/type/ManyToOneType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/ManyToOneType.java 2006-06-15 07:50:12 UTC (rev 10019) +++ trunk/Hibernate3/src/org/hibernate/type/ManyToOneType.java 2006-06-15 16:38:03 UTC (rev 10020) @@ -17,104 +17,110 @@ import org.hibernate.persister.entity.EntityPersister; /** - * A many-to-one association to an entity + * A many-to-one association to an entity. + * * @author Gavin King */ public class ManyToOneType extends EntityType { private final boolean ignoreNotFound; - - protected boolean isNullable() { - return ignoreNotFound; - } - - /** - * If we have <tt>not-found="ignore"</tt> association - * mapped to a formula, we always need to dirty check - * it, so we can update the second-level cache - */ - public boolean isAlwaysDirtyChecked() { - return ignoreNotFound; - } - - public int getColumnSpan(Mapping mapping) throws MappingException { - return getIdentifierOrUniqueKeyType(mapping).getColumnSpan(mapping); - } - public int[] sqlTypes(Mapping mapping) throws MappingException { - return getIdentifierOrUniqueKeyType(mapping).sqlTypes(mapping); + public ManyToOneType(String className) { + this( className, false ); } - public ManyToOneType(String className) { - this(className, false); - } - public ManyToOneType(String className, boolean lazy) { - super(className, null, !lazy, true, false); + super( className, null, !lazy, true, false ); this.ignoreNotFound = false; } public ManyToOneType( - String entityName, + String entityName, String uniqueKeyPropertyName, boolean lazy, - boolean unwrapProxy, + boolean unwrapProxy, boolean isEmbeddedInXML, - boolean ignoreNotFound - ) { - super(entityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy); + boolean ignoreNotFound) { + super( entityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy ); this.ignoreNotFound = ignoreNotFound; } - public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session) - throws HibernateException, SQLException { - getIdentifierOrUniqueKeyType( session.getFactory() ) - .nullSafeSet(st, getIdentifier(value, session), index, settable, session); + protected boolean isNullable() { + return ignoreNotFound; } - public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) - throws HibernateException, SQLException { - getIdentifierOrUniqueKeyType( session.getFactory() ) - .nullSafeSet(st, getIdentifier(value, session), index, session); + public boolean isAlwaysDirtyChecked() { + // If we have <tt>not-found="ignore"</tt> association mapped to a + // formula, we always need to dirty check it, so we can update the + // second-level cache + return ignoreNotFound; } public boolean isOneToOne() { return false; } + + public int getColumnSpan(Mapping mapping) throws MappingException { + // our column span is the number of columns in the PK + return getIdentifierOrUniqueKeyType( mapping ).getColumnSpan( mapping ); + } + public int[] sqlTypes(Mapping mapping) throws MappingException { + return getIdentifierOrUniqueKeyType( mapping ).sqlTypes( mapping ); + } + + public void nullSafeSet( + PreparedStatement st, + Object value, + int index, + boolean[] settable, + SessionImplementor session) throws HibernateException, SQLException { + getIdentifierOrUniqueKeyType( session.getFactory() ) + .nullSafeSet( st, getIdentifier( value, session ), index, settable, session ); + } + + public void nullSafeSet( + PreparedStatement st, + Object value, + int index, + SessionImplementor session) throws HibernateException, SQLException { + getIdentifierOrUniqueKeyType( session.getFactory() ) + .nullSafeSet( st, getIdentifier( value, session ), index, session ); + } + public ForeignKeyDirection getForeignKeyDirection() { return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT; } - public Object hydrate(ResultSet rs, String[] names, SessionImplementor session, Object owner) - throws HibernateException, SQLException { - - //return the (fully resolved) identifier value, but do not resolve - //to the actual referenced entity instance - + public Object hydrate( + ResultSet rs, + String[] names, + SessionImplementor session, + Object owner) throws HibernateException, SQLException { + // return the (fully resolved) identifier value, but do not resolve + // to the actual referenced entity instance + // NOTE: the owner of the association is not really the owner of the id! Serializable id = (Serializable) getIdentifierOrUniqueKeyType( session.getFactory() ) - .nullSafeGet(rs, names, session, null); //note that the owner of the association is not really the owner of the id! - - if (id!=null) scheduleBatchLoad(id, session); - + .nullSafeGet( rs, names, session, null ); + scheduleBatchLoadIfNeeded( id, session ); return id; } /** * Register the entity as batch loadable, if enabled */ - private void scheduleBatchLoad(Serializable id, SessionImplementor session) - throws MappingException { - - if (uniqueKeyPropertyName==null) { //cannot batch fetch by unique key - - EntityPersister persister = session.getFactory() - .getEntityPersister( getAssociatedEntityName() ); - + private void scheduleBatchLoadIfNeeded( + Serializable id, + SessionImplementor session) throws MappingException { + //cannot batch fetch by unique key (property-ref associations) + if ( uniqueKeyPropertyName == null && id != null ) { + EntityPersister persister = session.getFactory().getEntityPersister( getAssociatedEntityName() ); EntityKey entityKey = new EntityKey( id, persister, session.getEntityMode() ); - session.getPersistenceContext() - .getBatchFetchQueue() - .addBatchLoadableEntityKey( entityKey ); + if ( !session.getPersistenceContext().containsEntity( entityKey ) ) { + session.getPersistenceContext() + .getBatchFetchQueue() + .addBatchLoadableEntityKey( entityKey ); + } } } @@ -122,24 +128,33 @@ return false; } - public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session) - throws HibernateException { - - if (current==null) return old!=null; - if (old==null) return current!=null; - //the ids are fully resolved, so compare them with isDirty(), not isModified() + public boolean isModified( + Object old, + Object current, + boolean[] checkable, + SessionImplementor session) throws HibernateException { + if ( current == null ) { + return old!=null; + } + if ( old == null ) { + // we already know current is not null... + return true; + } + // the ids are fully resolved, so compare them with isDirty(), not isModified() return getIdentifierOrUniqueKeyType( session.getFactory() ) - .isDirty( old, getIdentifier(current, session), session ); + .isDirty( old, getIdentifier( current, session ), session ); } - public Serializable disassemble(Object value, SessionImplementor session, Object owner) - throws HibernateException { + public Serializable disassemble( + Object value, + SessionImplementor session, + Object owner) throws HibernateException { - if ( isNotEmbedded(session) ) { - return getIdentifierType(session).disassemble(value, session, owner); + if ( isNotEmbedded( session ) ) { + return getIdentifierType( session ).disassemble( value, session, owner ); } - if (value==null) { + if ( value == null ) { return null; } else { @@ -148,78 +163,84 @@ Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, - session - ); - if (id==null) { + session + ); + if ( id == null ) { throw new AssertionFailure( "cannot cache a reference to an object with a null id: " + - getAssociatedEntityName() - ); + getAssociatedEntityName() + ); } - return getIdentifierType(session).disassemble(id, session, owner); + return getIdentifierType( session ).disassemble( id, session, owner ); } } - public Object assemble(Serializable oid, SessionImplementor session, Object owner) - throws HibernateException { + public Object assemble( + Serializable oid, + SessionImplementor session, + Object owner) throws HibernateException { //TODO: currently broken for unique-key references (does not detect // change to unique key property of the associated object) Serializable id = assembleId( oid, session ); - if ( isNotEmbedded(session) ) return id; + if ( isNotEmbedded( session ) ) { + return id; + } - if (id==null) { + if ( id == null ) { return null; } else { - return resolveIdentifier(id, session); + return resolveIdentifier( id, session ); } } private Serializable assembleId(Serializable oid, SessionImplementor session) { - return (Serializable) getIdentifierType(session) - .assemble(oid, session, null); //the owner of the association is not the owner of the id + //the owner of the association is not the owner of the id + return ( Serializable ) getIdentifierType( session ).assemble( oid, session, null ); } public void beforeAssemble(Serializable oid, SessionImplementor session) { - if ( uniqueKeyPropertyName==null && oid!=null ) { - EntityPersister persister = session.getFactory().getEntityPersister( getAssociatedEntityName() ); - EntityKey key = new EntityKey( assembleId(oid, session), persister, session.getEntityMode() ); - session.getPersistenceContext().getBatchFetchQueue().addBatchLoadableEntityKey(key); - } + scheduleBatchLoadIfNeeded( assembleId( oid, session ), session ); } public boolean[] toColumnNullness(Object value, Mapping mapping) { - boolean[] result = new boolean[ getColumnSpan(mapping) ]; - if (value!=null) Arrays.fill(result, true); + boolean[] result = new boolean[ getColumnSpan( mapping ) ]; + if ( value != null ) { + Arrays.fill( result, true ); + } return result; } - public boolean isDirty(Object old, Object current, SessionImplementor session) - throws HibernateException { - - if ( isSame( old, current, session.getEntityMode() ) ) return false; - - Object oldid = getIdentifier(old, session); - Object newid = getIdentifier(current, session); - return getIdentifierType(session).isDirty( oldid, newid, session ); - + public boolean isDirty( + Object old, + Object current, + SessionImplementor session) throws HibernateException { + if ( isSame( old, current, session.getEntityMode() ) ) { + return false; + } + Object oldid = getIdentifier( old, session ); + Object newid = getIdentifier( current, session ); + return getIdentifierType( session ).isDirty( oldid, newid, session ); } - public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session) - throws HibernateException { - + public boolean isDirty( + Object old, + Object current, + boolean[] checkable, + SessionImplementor session) throws HibernateException { if ( isAlwaysDirtyChecked() ) { - return isDirty(old, current, session); + return isDirty( old, current, session ); } else { - if ( isSame( old, current, session.getEntityMode() ) ) return false; - - Object oldid = getIdentifier(old, session); - Object newid = getIdentifier(current, session); - return getIdentifierType(session).isDirty( oldid, newid, checkable, session ); + if ( isSame( old, current, session.getEntityMode() ) ) { + return false; + } + Object oldid = getIdentifier( old, session ); + Object newid = getIdentifier( current, session ); + return getIdentifierType( session ).isDirty( oldid, newid, checkable, session ); } } |