5

I want to create a sequence with prefix "CID_00001" (example):

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)   
private String id;

Is there any way to do this ?

ikos23
  • 4,879
  • 10
  • 41
  • 60
hetesh mohan
  • 87
  • 1
  • 9

2 Answers2

15

You can do that using a custom id generator.

The easiest way is to extend Hibernate's SequenceStyleGenerator, which implements the access to the database sequence (incl. a few interesting optimizations)

public class StringPrefixedSequenceIdGenerator extends SequenceStyleGenerator {

    public static final String VALUE_PREFIX_PARAMETER = "valuePrefix";
    public static final String VALUE_PREFIX_DEFAULT = "";
    private String valuePrefix;

    public static final String NUMBER_FORMAT_PARAMETER = "numberFormat";
    public static final String NUMBER_FORMAT_DEFAULT = "%d";
    private String numberFormat;

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        return valuePrefix + String.format(numberFormat, super.generate(session, object));
    }

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        super.configure(LongType.INSTANCE, params, serviceRegistry);
        valuePrefix = ConfigurationHelper.getString(VALUE_PREFIX_PARAMETER, params, VALUE_PREFIX_DEFAULT);
    numberFormat = ConfigurationHelper.getString(NUMBER_FORMAT_PARAMETER, params, NUMBER_FORMAT_DEFAULT);
    }
}

After you've implemented your own id generator, you can reference it in a @GenericGenerator annotation.

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_seq")
    @GenericGenerator(
        name = "book_seq", 
        strategy = "org.thoughts.on.java.generators.StringPrefixedSequenceIdGenerator", 
        parameters = {
            @Parameter(name = StringPrefixedSequenceIdGenerator.INCREMENT_PARAM, value = "50"),
            @Parameter(name = StringPrefixedSequenceIdGenerator.VALUE_PREFIX_PARAMETER, value = "CID_"),
            @Parameter(name = StringPrefixedSequenceIdGenerator.NUMBER_FORMAT_PARAMETER, value = "%05d") })
    private String id;

    ...
}
Thorben Janssen
  • 3,012
  • 9
  • 23
  • @ThorbenJanssen sir, doing this way we get hibernate_sequence table.how to get separate tables entity wise. Like ```@SequenceGenerator(name = "batch_seq", sequenceName = "batch_seq", initialValue = 1, allocationSize=1)``` – Dhanushka sasanka Sep 25 '19 at 17:55
  • Hi Thorben in this -- @Parameter(name = StringPrefixedSequenceIdGenerator.INCREMENT_PARAM, value = "50") . what does value 50 represent and what does changing the number changes in id generation ? – Hem M Jun 29 '20 at 10:11
  • I had pretty same implementation as your example. Now I'm wondering if we can use it type-safe in Hibernate 6? – NickNgn May 31 '23 at 10:00
  • I found the answer myself, since Hibernate 6.2 and later, @GenericGenerator provide `type` to help strategy declared prettier: https://docs.jboss.org/hibernate/orm/6.0/javadocs/org/hibernate/annotations/GenericGenerator.html – NickNgn May 31 '23 at 10:14
2

I think you are using the database sequence for generating the PK. So add a trigger before inserting into the table. e.g., (in oracle )

CREATE OR REPLACE TRIGGER sometable_trigger  
BEFORE INSERT ON SomeTable
FOR EACH ROW

BEGIN
  SELECT 'CID_' || to_char(sometable_seq.NEXTVAL, "00009")
  INTO   :new.id
  FROM   dual;
END;
/

assumption: sequence name as "sometable_seq" and id column name id

mallikarjun
  • 1,862
  • 5
  • 23
  • 47