/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.id; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.insert.AbstractSelectingDelegate; import org.hibernate.id.insert.IdentifierGeneratingInsert; import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.Type; /** * A generator that selects the just inserted row to determine the identifier * value assigned by the database. The correct row is located using a unique * key. * <p/> * One mapping parameter is required: key (unless a natural-id is defined in the mapping). * * @author Gavin King */ public class SelectGenerator extends AbstractPostInsertGenerator implements Configurable { private String uniqueKeyPropertyName; @Override public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { uniqueKeyPropertyName = params.getProperty( "key" ); } public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate( PostInsertIdentityPersister persister, Dialect dialect, boolean isGetGeneratedKeysEnabled) throws HibernateException { return new SelectGeneratorDelegate( persister, dialect, uniqueKeyPropertyName ); } private static String determineNameOfPropertyToUse(PostInsertIdentityPersister persister, String supplied) { if ( supplied != null ) { return supplied; } int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties(); if ( naturalIdPropertyIndices == null ) { throw new IdentifierGenerationException( "no natural-id property defined; need to specify [key] in " + "generator parameters" ); } if ( naturalIdPropertyIndices.length > 1 ) { throw new IdentifierGenerationException( "select generator does not currently support composite " + "natural-id properties; need to specify [key] in generator parameters" ); } if ( persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) { throw new IdentifierGenerationException( "natural-id also defined as insert-generated; need to specify [key] " + "in generator parameters" ); } return persister.getPropertyNames()[naturalIdPropertyIndices[0]]; } /** * The delegate for the select generation strategy. */ public static class SelectGeneratorDelegate extends AbstractSelectingDelegate implements InsertGeneratedIdentifierDelegate { private final PostInsertIdentityPersister persister; private final Dialect dialect; private final String uniqueKeyPropertyName; private final Type uniqueKeyType; private final Type idType; private final String idSelectString; private SelectGeneratorDelegate( PostInsertIdentityPersister persister, Dialect dialect, String suppliedUniqueKeyPropertyName) { super( persister ); this.persister = persister; this.dialect = dialect; this.uniqueKeyPropertyName = determineNameOfPropertyToUse( persister, suppliedUniqueKeyPropertyName ); idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName ); uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName ); idType = persister.getIdentifierType(); } public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { return new IdentifierGeneratingInsert( dialect ); } // AbstractSelectingDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected String getSelectSQL() { return idSelectString; } protected void bindParameters( SharedSessionContractImplementor session, PreparedStatement ps, Object entity) throws SQLException { Object uniqueKeyValue = persister.getPropertyValue( entity, uniqueKeyPropertyName ); uniqueKeyType.nullSafeSet( ps, uniqueKeyValue, 1, session ); } protected Serializable getResult( SharedSessionContractImplementor session, ResultSet rs, Object entity) throws SQLException { if ( !rs.next() ) { throw new IdentifierGenerationException( "the inserted row could not be located by the unique key: " + uniqueKeyPropertyName ); } return (Serializable) idType.nullSafeGet( rs, persister.getRootTableKeyColumnNames(), session, entity ); } } }