HIBERNATE JBoss.org
 |  Register  | 
     
News 
About 
   Feature List 
   Road Map 
Documentation 
   Related Projects 
   External Documentation 
Download 
Forum & Mailinglists 
Support & Training 
JIRA Issue Tracking
Wiki Community Area


Hibernate Public Training Courses


Get Hibernate in Action eBook!


JavaWorld 2003 Finalist


Jolt Award 2004 Winner
      
Documentation > Community Area > NativeHiloGenerator

NativeHiloGenerator

Hibernate comes by default with several Identifier generation strategies.

The native strategy is intresting if you have to support different types of database without changing your mappings. Depending on your database capabilities, this strategy will use:

  • the identity where supported (eg. SQL Server)
  • the sequence where supported (eg. Oracle)
  • otherwise the hilo strategy.

Unfortunately, the identity and sequence strategies are not very efficient since they require at least two SQL queries by insert (one for the actual insert, another to fetch the identifier value).


Another more efficient strategy, the nativehilo, may be as follows:

  • use the seqhilo when database sequence are supported (eg. Oracle)
  • otherwise the hilo strategy.

Below is an example of such generator. It behaves like a proxy for seqhilo or hilo depending on the database capabilities.

It supports the same configuration parameters as the seqhilo strategy where the sequence parameter gives the sequence name when seqhilo is used or the table name when hilo is used.

package be.modulo1.framework.hibernate.id;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Properties;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.dialect.Dialect;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.id.Configurable;
import net.sf.hibernate.id.IdentifierGenerator;
import net.sf.hibernate.id.PersistentIdentifierGenerator;
import net.sf.hibernate.id.SequenceHiLoGenerator;
import net.sf.hibernate.id.TableHiLoGenerator;
import net.sf.hibernate.type.Type;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * <b>nativehilo</b><br>
 * <br>
 * An <tt>IdentifierGenerator</tt> that combines a hi/lo algorithm with an underlying
 * oracle-style sequence that generates hi values if supported or the TableHiLo 
 * generator otherwise.
 * <br>
 * Mapping parameters supported: sequence, max_lo, parameters (the same as the SequenceHiLoGenerator).
 *
 * @see net.sf.hibernate.id.TableHiLoGenerator
 * @see net.sf.hibernate.id.SequenceHiLoGenerator
 * 
 * @author Bertrand Renuart
 */
public class NativeHiLoGenerator implements IdentifierGenerator, 
                                            PersistentIdentifierGenerator, 
                                            Configurable 
{
    // logger
    private static final Log log = LogFactory.getLog(NativeHiLoGenerator.class);
    
    // reference to the underlying generator to which we delegate the work
    private IdentifierGenerator proxiedIdGen;
    
    
    //
    // -- Constructor(s) ------------------------------------------------------
    //
    /**
     * Construct a new NativeHiLoGenerator
     */
    public NativeHiLoGenerator() {
        super();
    }

    
    //
    // -- IdentifierGenerator interface implementation ------------------------
    //
    
    /* (non-Javadoc)
     * @see net.sf.hibernate.id.IdentifierGenerator#generate(net.sf.hibernate.engine.SessionImplementor, java.lang.Object)
     */
    public Serializable generate(SessionImplementor session, Object object)
            throws SQLException, HibernateException 
    {
        return proxiedIdGen.generate(session, object);
    }


    
    //
    // -- PersistentIdentifierGenerator interface implementation ------------------------
    //

    
    /* (non-Javadoc)
     * @see net.sf.hibernate.id.PersistentIdentifierGenerator#generatorKey()
     */
    public Object generatorKey() {
        if( proxiedIdGen instanceof PersistentIdentifierGenerator )
            return ((PersistentIdentifierGenerator)proxiedIdGen).generatorKey();
        else
            return this; // not sure it is a good solution, but we won't fall in this case with the two generators defined below ;-) 
    }
    

    /* (non-Javadoc)
     * @see net.sf.hibernate.id.PersistentIdentifierGenerator#sqlCreateStrings(net.sf.hibernate.dialect.Dialect)
     */
    public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
        if( proxiedIdGen instanceof PersistentIdentifierGenerator )
            return ((PersistentIdentifierGenerator)proxiedIdGen).sqlCreateStrings(dialect);
        else
            return new String[]{}; // safe, supported by caller
    }
    

    /* (non-Javadoc)
     * @see net.sf.hibernate.id.PersistentIdentifierGenerator#sqlDropString(net.sf.hibernate.dialect.Dialect)
     */
    public String sqlDropString(Dialect dialect) throws HibernateException {
        if( proxiedIdGen instanceof PersistentIdentifierGenerator )
            return ((PersistentIdentifierGenerator)proxiedIdGen).sqlDropString(dialect);
        else
            return null; //safe, supported by caller
    }
    
    

    //
    // -- Configurable interface implementation -------------------------------
    //
    
    /* (non-Javadoc)
     * @see net.sf.hibernate.id.Configurable#configure(net.sf.hibernate.type.Type, java.util.Properties, net.sf.hibernate.dialect.Dialect)
     */
    public void configure(Type type, Properties params, Dialect dialect)
            throws MappingException 
    {
        // if the dialect supports SEQUENCE(s), use them
        Class generatorClass = null;
        if ( dialect.supportsSequences() ) 
        {
            log.debug("Support for SEQUENCE detected - delegate to SequenceHiLoGenerator");
            generatorClass = SequenceHiLoGenerator.class;
        }
        
        // otherwise use the TableHiLoGenerator
        else
        {
            log.debug("No support for SEQUENCE detected - delegate to TableHiLoGenerator");
            generatorClass = TableHiLoGenerator.class;
            
            // convert SequenceHiLoGenerator properties to a format acceptable for the TableHiLoGenerator

            // -- max_lo -> max_lo
            if( ! SequenceHiLoGenerator.MAX_LO.equals(TableHiLoGenerator.MAX_LO) ) 
            {
                String value = params.getProperty(SequenceHiLoGenerator.MAX_LO);
                if( value != null ) params.setProperty(TableHiLoGenerator.MAX_LO, value);
            }
            
            // -- sequence name -> table name
            if( ! SequenceHiLoGenerator.SEQUENCE.equals(TableHiLoGenerator.TABLE) ) 
            {
                String value = params.getProperty(SequenceHiLoGenerator.SEQUENCE);
                if( value != null ) params.setProperty(TableHiLoGenerator.TABLE, value);
            }
        }
        
        
        // create a new instance
        IdentifierGenerator idgen = null;
        try {
            idgen = (IdentifierGenerator) generatorClass.newInstance();
        }
        catch (Exception e) {
            throw new MappingException("could not instantiate id generator", e);
        }
        
        
        // configure it if it supports configuration (
        if (idgen instanceof Configurable)
            ((Configurable) idgen).configure(type, params, dialect);

        
        // ok
        this.proxiedIdGen = idgen;
    }
}
      

coWiki