32

Is there a way to specify distinct sequences for each table in Hibernate, if the ID is defined on a mapped superclass?

All entities in our application extend a superclass called DataObject like this:

@MappedSuperclass
public abstract class DataObject implements Serializable {
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id")
    private int id;
}

@Entity
@Table(name = "entity_a")
public class EntityA extends DataObject { ... }

@Entity
@Table(name = "entity_b")
public class EntityB extends DataObject { ... }

This causes all entities to use a shared sequence, the default hibernate_sequence.

What I would like to do is use a separate sequence for each entity, for example entity_a_sequence and entity_b_sequence in the example above. If the ID were specified on the subclasses then I could use the @SequenceGenerator annotation to specify a sequence for each entity, but in this case the ID is on the superclass. Given that ID is in the superclass, is there a way I can use a separate sequence for each entity — and if so, how?

(We are using PostgreSQL 8.3, in case that's relevant)

gutch
  • 6,959
  • 3
  • 36
  • 53

5 Answers5

47

Have you tried doing it this way ?

@MappedSuperclass
public abstract class DataObject implements Serializable {
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
    @Column(name = "id")
    private int id;
}

@Entity
@SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entityaseq")
@Table(name = "entity_a")
public class EntityA extends DataObject { 

}

@Entity
@SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entitybseq")
@Table(name = "entity_b")
public class EntityB extends DataObject {

}

I'm sorry I don't have the required environment to test it right now but I'll try it later.

  • 2
    Yes — it does work! I had tried something similar but kept getting a `org.hibernate.AnnotationException: Unknown Id.generator: idgen`. However your code worked fine; it turns out that I forgot to include the `@SequenceGenerator` on one of the subclasses in my first attempt. So the answer is that it does work, as long as every entity subclass has the @SequenceGenerator annotation on it. – gutch Dec 30 '10 at 10:49
  • Finally an answer that works. This was baffling me for days. However a table `hibernate_sequence` still gets created, should I ignore it or is there a way to disable it? – Valamorde Jun 20 '18 at 11:04
  • 4
    This works on versions < 5.2.14 and >= 5.2.17. see https://hibernate.atlassian.net/browse/HHH-12329, http://in.relation.to/2018/04/26/hibernate-orm-5217-final-release/ – Muhammad Hewedy Sep 30 '18 at 22:37
9

We use this in the abstract superclass of all of our JPA entities:

@Id
@GeneratedValue(generator = "pooled")
@GenericGenerator(name = "pooled", strategy = "org.hibernate.id.enhanced.TableGenerator", parameters = {
        @org.hibernate.annotations.Parameter(name = "value_column_name", value = "sequence_next_hi_value"),
        @org.hibernate.annotations.Parameter(name = "prefer_entity_table_as_segment_value", value = "true"),
        @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled-lo"),
        @org.hibernate.annotations.Parameter(name = "increment_size", value = "100")})
private Long id;

It's a bit verbose, but it allows setting the prefer_entity_table_as_segment_value which means you don't need to repeat the id field or the generator annotations in the subclasses.

Frans
  • 3,670
  • 1
  • 31
  • 29
7

I was not quite happy about the need to declare the sequence name on each class individually. I have checked the source code and came up with this solution:

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.id.enhanced.SequenceStyleGenerator;

// ...

@Id
@GeneratedValue(generator = "sequenceIdGenerator")
@GenericGenerator(
        name = "sequenceIdGenerator", 
        strategy = "sequence",
        parameters = @Parameter(
                name = SequenceStyleGenerator.CONFIG_PREFER_SEQUENCE_PER_ENTITY,
                value = "true"))
@Column(updatable = false, nullable = false)
protected Long id;
Jens Piegsa
  • 7,399
  • 5
  • 58
  • 106
  • 1
    As an extension to this, with this approach hibernate will expect to find for an entity a sequence named tableName_SEQ (e.g. CUSTOMER_SEQ). If someone has a different suffix for the sequence name he needs to use the parameter CONFIG_SEQUENCE_PER_ENTITY_SUFFIX as well. – gred Oct 11 '22 at 11:38
2

IHMO there is better way to do this:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

It works in my app.

Gumovvy Steven
  • 101
  • 2
  • 10
  • 10
    That uses the database's native method for generating IDs (e.g. auto_increment in MySQL) and is very inefficient for bulk inserts as the inserts must then be done one-by-one to get the generated IDs from the database driver. – Frans May 04 '15 at 15:54
0

TABLE generation stretergy uses separate db sequence for each table but it is little expensive operation

Nagappa L M
  • 1,452
  • 4
  • 20
  • 33