Open Source Repository

Home /hibernate/hibernate-3.2.6.ga | Repository Home


org/hibernate/type/ManyToOneType.java
//$Id: ManyToOneType.java 10020 2006-06-15 16:38:03Z [email protected] $
package org.hibernate.type;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;

import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.ForeignKeys;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;

/**
 * A many-to-one association to an entity.
 *
 @author Gavin King
 */
public class ManyToOneType extends EntityType {
  
  private final boolean ignoreNotFound;

  public ManyToOneType(String className) {
    thisclassName, false );
  }

  public ManyToOneType(String className, boolean lazy) {
    superclassName, null, !lazy, true, false );
    this.ignoreNotFound = false;
  }

  public ManyToOneType(
      String entityName,
      String uniqueKeyPropertyName,
      boolean lazy,
      boolean unwrapProxy,
      boolean isEmbeddedInXML,
      boolean ignoreNotFound) {
    superentityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy );
    this.ignoreNotFound = ignoreNotFound;
  }

  protected boolean isNullable() {
    return ignoreNotFound;
  }

  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 mappingthrows MappingException {
    // our column span is the number of columns in the PK
    return getIdentifierOrUniqueKeyTypemapping ).getColumnSpanmapping );
  }

  public int[] sqlTypes(Mapping mappingthrows MappingException {
    return getIdentifierOrUniqueKeyTypemapping ).sqlTypesmapping );
  }

  public void nullSafeSet(
      PreparedStatement st,
      Object value,
      int index,
      boolean[] settable,
      SessionImplementor sessionthrows HibernateException, SQLException {
    getIdentifierOrUniqueKeyTypesession.getFactory() )
        .nullSafeSetst, getIdentifiervalue, session ), index, settable, session );
  }

  public void nullSafeSet(
      PreparedStatement st,
      Object value,
      int index,
      SessionImplementor sessionthrows HibernateException, SQLException {
    getIdentifierOrUniqueKeyTypesession.getFactory() )
        .nullSafeSetst, getIdentifiervalue, session ), index, session );
  }

  public ForeignKeyDirection getForeignKeyDirection() {
    return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
  }

  public Object hydrate(
      ResultSet rs,
      String[] names,
      SessionImplementor session,
      Object ownerthrows 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 = (SerializablegetIdentifierOrUniqueKeyTypesession.getFactory() )
        .nullSafeGetrs, names, session, null );
    scheduleBatchLoadIfNeededid, session );
    return id;
  }

  /**
   * Register the entity as batch loadable, if enabled
   */
  private void scheduleBatchLoadIfNeeded(
      Serializable id,
      SessionImplementor sessionthrows MappingException {
    //cannot batch fetch by unique key (property-ref associations)
    if uniqueKeyPropertyName == null && id != null ) {
      EntityPersister persister = session.getFactory().getEntityPersistergetAssociatedEntityName() );
      EntityKey entityKey = new EntityKeyid, persister, session.getEntityMode() );
      if !session.getPersistenceContext().containsEntityentityKey ) ) {
        session.getPersistenceContext()
            .getBatchFetchQueue()
            .addBatchLoadableEntityKeyentityKey );
      }
    }
  }
  
  public boolean useLHSPrimaryKey() {
    return false;
  }

  public boolean isModified(
      Object old,
      Object current,
      boolean[] checkable,
      SessionImplementor sessionthrows 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 getIdentifierOrUniqueKeyTypesession.getFactory() )
        .isDirtyold, getIdentifiercurrent, session ), session );
  }

  public Serializable disassemble(
      Object value,
      SessionImplementor session,
      Object ownerthrows HibernateException {

    if isNotEmbeddedsession ) ) {
      return getIdentifierTypesession ).disassemblevalue, session, owner );
    }
    
    if value == null ) {
      return null;
    }
    else {
      // cache the actual id of the object, not the value of the
      // property-ref, which might not be initialized
      Object id = ForeignKeys.getEntityIdentifierIfNotUnsaved
          getAssociatedEntityName()
          value, 
          session
      );
      if id == null ) {
        throw new AssertionFailure(
            "cannot cache a reference to an object with a null id: " 
            getAssociatedEntityName()
        );
      }
      return getIdentifierTypesession ).disassembleid, session, owner );
    }
  }

  public Object assemble(
      Serializable oid,
      SessionImplementor session,
      Object ownerthrows HibernateException {
    
    //TODO: currently broken for unique-key references (does not detect
    //      change to unique key property of the associated object)
    
    Serializable id = assembleIdoid, session );

    if isNotEmbeddedsession ) ) {
      return id;
    }
    
    if id == null ) {
      return null;
    }
    else {
      return resolveIdentifierid, session );
    }
  }

  private Serializable assembleId(Serializable oid, SessionImplementor session) {
    //the owner of the association is not the owner of the id
    return Serializable getIdentifierTypesession ).assembleoid, session, null );
  }

  public void beforeAssemble(Serializable oid, SessionImplementor session) {
    scheduleBatchLoadIfNeededassembleIdoid, session ), session );
  }
  
  public boolean[] toColumnNullness(Object value, Mapping mapping) {
    boolean[] result = new booleangetColumnSpanmapping ) ];
    if value != null ) {
      Arrays.fillresult, true );
    }
    return result;
  }
  
  public boolean isDirty(
      Object old,
      Object current,
      SessionImplementor sessionthrows HibernateException {
    if isSameold, current, session.getEntityMode() ) ) {
      return false;
    }
    Object oldid = getIdentifierold, session );
    Object newid = getIdentifiercurrent, session );
    return getIdentifierTypesession ).isDirtyoldid, newid, session );
  }

  public boolean isDirty(
      Object old,
      Object current,
      boolean[] checkable,
      SessionImplementor sessionthrows HibernateException {
    if isAlwaysDirtyChecked() ) {
      return isDirtyold, current, session );
    }
    else {
      if isSameold, current, session.getEntityMode() ) ) {
        return false;
      }
      Object oldid = getIdentifierold, session );
      Object newid = getIdentifiercurrent, session );
      return getIdentifierTypesession ).isDirtyoldid, newid, checkable, session );
    }
    
  }

}