HHH-6790 - Sequence per entity for enhanced SequenceStyleGenerator
This commit is contained in:
parent
fc068be040
commit
cfa729d8b3
|
@ -1883,6 +1883,19 @@ class Person {
|
|||
used to hold the value.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>prefer_sequence_per_entity</literal> (optional -
|
||||
defaults to <literal>false</literal>): should we create
|
||||
separate sequence for each entity that share current generator
|
||||
based on its name?</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>sequence_per_entity_suffix</literal> (optional -
|
||||
defaults to <literal>_SEQ</literal>): suffix added to the name
|
||||
of a dedicated sequence.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>optimizer</literal> (optional - defaults to
|
||||
<literal>none</literal>): See <xref
|
||||
|
|
|
@ -52,7 +52,12 @@ public interface IdentifierGenerator {
|
|||
* The configuration parameter holding the entity name
|
||||
*/
|
||||
public static final String ENTITY_NAME = "entity_name";
|
||||
|
||||
|
||||
/**
|
||||
* The configuration parameter holding the JPA entity name
|
||||
*/
|
||||
public static final String JPA_ENTITY_NAME = "jpa_entity_name";
|
||||
|
||||
/**
|
||||
* Generate a new identifier.
|
||||
* @param session
|
||||
|
|
|
@ -48,6 +48,12 @@ import org.hibernate.type.Type;
|
|||
* a sequence. These variations are encapsulated by the {@link DatabaseStructure}
|
||||
* interface internally.
|
||||
* <p/>
|
||||
* <b>NOTE</b> that by default we utilize a single database sequence for all
|
||||
* generators. The configuration parameter {@link #CONFIG_PREFER_SEQUENCE_PER_ENTITY}
|
||||
* can be used to create dedicated sequence for each entity based on its name.
|
||||
* Sequence suffix can be controlled with {@link #CONFIG_SEQUENCE_PER_ENTITY_SUFFIX}
|
||||
* option.
|
||||
* <p/>
|
||||
* General configuration parameters:
|
||||
* <table>
|
||||
* <tr>
|
||||
|
@ -96,6 +102,7 @@ import org.hibernate.type.Type;
|
|||
* </table>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class SequenceStyleGenerator
|
||||
implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable {
|
||||
|
@ -119,6 +126,10 @@ public class SequenceStyleGenerator
|
|||
|
||||
public static final String FORCE_TBL_PARAM = "force_table_use";
|
||||
|
||||
public static final String CONFIG_PREFER_SEQUENCE_PER_ENTITY = "prefer_sequence_per_entity";
|
||||
public static final String CONFIG_SEQUENCE_PER_ENTITY_SUFFIX = "sequence_per_entity_suffix";
|
||||
public static final String DEF_SEQUENCE_SUFFIX = "_SEQ";
|
||||
|
||||
|
||||
// table-specific parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
public static final String VALUE_COLUMN_PARAM = "value_column";
|
||||
|
@ -209,8 +220,13 @@ public class SequenceStyleGenerator
|
|||
* @return The sequence name
|
||||
*/
|
||||
protected String determineSequenceName(Properties params, Dialect dialect) {
|
||||
String sequencePerEntitySuffix = ConfigurationHelper.getString( CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX );
|
||||
// JPA_ENTITY_NAME value honors <class ... entity-name="..."> (HBM) and @Entity#name (JPA) overrides.
|
||||
String sequenceName = ConfigurationHelper.getBoolean( CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false )
|
||||
? params.getProperty( JPA_ENTITY_NAME ) + sequencePerEntitySuffix
|
||||
: DEF_SEQUENCE_NAME;
|
||||
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
|
||||
String sequenceName = ConfigurationHelper.getString( SEQUENCE_PARAM, params, DEF_SEQUENCE_NAME );
|
||||
sequenceName = ConfigurationHelper.getString( SEQUENCE_PARAM, params, sequenceName );
|
||||
if ( sequenceName.indexOf( '.' ) < 0 ) {
|
||||
sequenceName = normalizer.normalizeIdentifierQuoting( sequenceName );
|
||||
String schemaName = params.getProperty( SCHEMA );
|
||||
|
|
|
@ -151,6 +151,7 @@ public class SimpleValue implements KeyValue {
|
|||
//pass the entity-name, if not a collection-id
|
||||
if (rootClass!=null) {
|
||||
params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
|
||||
params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
|
||||
}
|
||||
|
||||
//init the table here instead of earlier, so that we can get a quoted table name
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package org.hibernate.test.annotations.id.generationmappings;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "DEDICATED_SEQ_TBL1")
|
||||
public class DedicatedSequenceEntity1 implements Serializable {
|
||||
public static final String SEQUENCE_SUFFIX = "_GEN";
|
||||
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "SequencePerEntityGenerator")
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.hibernate.test.annotations.id.generationmappings;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Entity(name = DedicatedSequenceEntity2.ENTITY_NAME)
|
||||
@Table(name = "DEDICATED_SEQ_TBL2")
|
||||
public class DedicatedSequenceEntity2 implements Serializable {
|
||||
public static final String ENTITY_NAME = "DEDICATED2";
|
||||
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "SequencePerEntityGenerator")
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,9 @@ import org.hibernate.id.IdentifierGenerator;
|
|||
import org.hibernate.id.enhanced.OptimizerFactory;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.enhanced.TableGenerator;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -43,6 +45,7 @@ import static org.junit.Assert.assertTrue;
|
|||
* hibernate generators using the new scheme
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class NewGeneratorMappingsTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
|
@ -51,10 +54,17 @@ public class NewGeneratorMappingsTest extends BaseCoreFunctionalTestCase {
|
|||
MinimalSequenceEntity.class,
|
||||
CompleteSequenceEntity.class,
|
||||
AutoEntity.class,
|
||||
MinimalTableEntity.class
|
||||
MinimalTableEntity.class,
|
||||
DedicatedSequenceEntity1.class,
|
||||
DedicatedSequenceEntity2.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getAnnotatedPackages() {
|
||||
return new String[] { this.getClass().getPackage().getName() };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
|
@ -119,4 +129,28 @@ public class NewGeneratorMappingsTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals( 50, tabGenerator.getIncrementSize() );
|
||||
assertTrue( OptimizerFactory.PooledOptimizer.class.isInstance( tabGenerator.getOptimizer() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-6790")
|
||||
public void testSequencePerEntity() {
|
||||
// Checking first entity.
|
||||
EntityPersister persister = sessionFactory().getEntityPersister( DedicatedSequenceEntity1.class.getName() );
|
||||
IdentifierGenerator generator = persister.getIdentifierGenerator();
|
||||
assertTrue( SequenceStyleGenerator.class.isInstance( generator ) );
|
||||
SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator;
|
||||
assertEquals(
|
||||
StringHelper.unqualifyEntityName( DedicatedSequenceEntity1.class.getName() ) + DedicatedSequenceEntity1.SEQUENCE_SUFFIX,
|
||||
seqGenerator.getDatabaseStructure().getName()
|
||||
);
|
||||
|
||||
// Checking second entity.
|
||||
persister = sessionFactory().getEntityPersister( DedicatedSequenceEntity2.class.getName() );
|
||||
generator = persister.getIdentifierGenerator();
|
||||
assertTrue( SequenceStyleGenerator.class.isInstance( generator ) );
|
||||
seqGenerator = (SequenceStyleGenerator) generator;
|
||||
assertEquals(
|
||||
DedicatedSequenceEntity2.ENTITY_NAME + DedicatedSequenceEntity1.SEQUENCE_SUFFIX,
|
||||
seqGenerator.getDatabaseStructure().getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
@GenericGenerator(name = "SequencePerEntityGenerator",
|
||||
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
|
||||
parameters = {
|
||||
@Parameter(name = "prefer_sequence_per_entity", value = "true"),
|
||||
@Parameter(name = "sequence_per_entity_suffix", value = DedicatedSequenceEntity1.SEQUENCE_SUFFIX)
|
||||
}
|
||||
|
||||
)
|
||||
package org.hibernate.test.annotations.id.generationmappings;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
|
@ -28,6 +28,8 @@ import org.junit.Test;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.test.annotations.id.generationmappings.DedicatedSequenceEntity1;
|
||||
import org.hibernate.test.annotations.id.generationmappings.DedicatedSequenceEntity2;
|
||||
import org.hibernate.test.annotations.id.sequences.entities.Ball;
|
||||
import org.hibernate.test.annotations.id.sequences.entities.BreakDance;
|
||||
import org.hibernate.test.annotations.id.sequences.entities.Computer;
|
||||
|
@ -47,6 +49,7 @@ import org.hibernate.test.annotations.id.sequences.entities.Store;
|
|||
import org.hibernate.test.annotations.id.sequences.entities.Tree;
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
@ -54,6 +57,7 @@ import static junit.framework.Assert.assertNotNull;
|
|||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
|
||||
|
@ -291,6 +295,23 @@ public class IdTest extends BaseCoreFunctionalTestCase {
|
|||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-6790")
|
||||
public void testSequencePerEntity() {
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
DedicatedSequenceEntity1 entity1 = new DedicatedSequenceEntity1();
|
||||
DedicatedSequenceEntity2 entity2 = new DedicatedSequenceEntity2();
|
||||
session.persist( entity1 );
|
||||
session.persist( entity2 );
|
||||
session.getTransaction().commit();
|
||||
|
||||
assertEquals( 1, entity1.getId().intValue() );
|
||||
assertEquals( 1, entity2.getId().intValue() );
|
||||
|
||||
session.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnDefinition() {
|
||||
Column idCol = ( Column ) configuration().getClassMapping( Ball.class.getName() )
|
||||
|
@ -325,7 +346,8 @@ public class IdTest extends BaseCoreFunctionalTestCase {
|
|||
Department.class, Dog.class, Computer.class, Home.class,
|
||||
Phone.class, Tree.class, FirTree.class, Footballer.class,
|
||||
SoundSystem.class, Furniture.class, GoalKeeper.class,
|
||||
BreakDance.class, Monkey.class
|
||||
BreakDance.class, Monkey.class, DedicatedSequenceEntity1.class,
|
||||
DedicatedSequenceEntity2.class
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -333,7 +355,8 @@ public class IdTest extends BaseCoreFunctionalTestCase {
|
|||
protected String[] getAnnotatedPackages() {
|
||||
return new String[] {
|
||||
"org.hibernate.test.annotations",
|
||||
"org.hibernate.test.annotations.id"
|
||||
"org.hibernate.test.annotations.id",
|
||||
"org.hibernate.test.annotations.id.generationmappings"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.id.IdentifierGeneratorHelper.BasicHolder;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertClassAssignability;
|
||||
|
@ -36,11 +37,12 @@ import static org.junit.Assert.assertEquals;
|
|||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class BasicSequenceTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] { "idgen/enhanced/sequence/Basic.hbm.xml" };
|
||||
return new String[] { "idgen/enhanced/sequence/Basic.hbm.xml", "idgen/enhanced/sequence/Dedicated.hbm.xml" };
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -71,4 +73,25 @@ public class BasicSequenceTest extends BaseCoreFunctionalTestCase {
|
|||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-6790")
|
||||
public void testSequencePerEntity() {
|
||||
final String overriddenEntityName = "SpecialEntity";
|
||||
EntityPersister persister = sessionFactory().getEntityPersister( overriddenEntityName );
|
||||
assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() );
|
||||
SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getIdentifierGenerator();
|
||||
assertEquals( overriddenEntityName + SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX, generator.getDatabaseStructure().getName() );
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Entity entity1 = new Entity( "1" );
|
||||
s.save( overriddenEntityName, entity1 );
|
||||
Entity entity2 = new Entity( "2" );
|
||||
s.save( overriddenEntityName, entity2 );
|
||||
s.getTransaction().commit();
|
||||
|
||||
assertEquals( 1, entity1.getId().intValue() );
|
||||
assertEquals( 2, entity2.getId().intValue() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
Demonstrates use of the enhanced sequence-based identifier
|
||||
generator, with dedicated sequence for each entity.
|
||||
-->
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.idgen.enhanced.sequence">
|
||||
|
||||
<class name="Entity" table="ID_SEQ_BSC_ENTITY" entity-name="SpecialEntity">
|
||||
<id name="id" column="ID" type="long">
|
||||
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator">
|
||||
<param name="prefer_sequence_per_entity">true</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="name" type="string"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
Loading…
Reference in New Issue