38

I'm using JPA2 with Hibernate and try to introduce a common base class for my entities. So far it looks like that:

@MappedSuperclass
public abstract class BaseEntity {

    @Id
    private Long id;

    @Override
    public int hashCode() {
        // ...
    }

    @Override
    public boolean equals(Object obj) {
        // ...
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

However, for every table theres a sequence $entityname_seq which I want to use as my sequence generator. How can I set that from my subclass? I think I need to override @GeneratedValue and create a new SequenceGenerator with @SequenceGenerator.

atamanroman
  • 11,607
  • 7
  • 57
  • 81

4 Answers4

42

Yes, it is possible. You can override the default generator name with the @SequenceGenerator annotation.

  • Base class
    @MappedSuperclass
    public abstract class PersistentEntity implements Serializable
    {
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "default_gen")
        protected Long id = 0L;

        public Long getId()
        {
            return id;
        }

        public void setId(Long id)
        { 
            this.id = id;
        }
    }
  • Sequence (SQL)

    create sequence role_seq;
  • Derived class

    @Entity
    @Table(name = "role")
    @SequenceGenerator(name = "default_gen", sequenceName = "role_seq", allocationSize = 1)
    public class Role extends PersistentEntity implements Serializable
    {
        private static final long serialVersionUID = 1L;

        @NotNull
        @Size(max = 32)
        private String name;

        public String getName()
        {
             return name;
        }

        public void setName(String name)
        {
             this.name = name;
        }   
    }
  • This approach worked fine in Hibernate 4.1.x, but it didn't in EclipseLink 2.x.

edit

  • As per the comment, it seems to be working with EclipseLink 2.6.1-RC1.
rbento
  • 9,919
  • 3
  • 61
  • 61
  • 1
    I've tested with EclipseLink 2.6.1-RC1 and it worked too. – leocborges Aug 11 '15 at 14:39
  • That's great news. Thank you! I'm gonna edit the answer. – rbento Aug 11 '15 at 14:57
  • An addition all subclasses must have the @SequenceGenerator defined otherwise errors will be thrown for the mapping – Stephen Senkomago Musoke Aug 29 '15 at 12:28
  • 7
    This is an incorrect solution. It will only work as long as you only have one sub-class of `PersistentEntity`. Say you create entity "Group" which also extends `PersistentEntity`. You'll then get error because Sequence Generator `default_gen` is defined twice within the same Persistency Unit. (EclipseLink 2.6.2) – peterh Mar 25 '16 at 12:15
  • @peterh Please check the full post, see the bottom lines. At the time it was answered it worked with hibernate but didn't even worked with EclipseLink and there is an edit later. It seemed to solve the OP's problem as well as for many other users. I'm sorry it didn't work for you. Feel free to contribute with you solution. – rbento Mar 25 '16 at 20:34
  • @rbento. Point taken. Yes, I should have said it is a no-longer-working solution in today's world and with recent EclipseLink. It may still be working fine with Hibernate, dunno. I don't doubt it have worked in the past. I'm afraid I haven't found a decent solution myself with EclipseLink. – peterh Mar 26 '16 at 09:21
  • 3
    Indeed as specified by JEE-7 "The scope of the generator name is global to the persistence unit (across all generator types)." So even if it works at some time with some implementations it is not standard behavior. – benjamin.donze May 11 '16 at 07:47
  • Unlike some noted here, it works for me with Spring Boot JPA and Hibernate. See my long answer here: https://stackoverflow.com/a/58543347/488265 – Jonas Gröger Oct 24 '19 at 14:18
  • Does this work for `IDENTITY` strategy? – TheRealChx101 Sep 18 '21 at 13:07
  • As for hibernate 5.4 this solution also does not work. – Aleksandr Savvopulo Sep 11 '22 at 16:35
  • 1
    @AleksandrSavvopulo - It does still work for me with hibernate 5.6.10. – icyerasor Feb 08 '23 at 13:56
15

In JPA that cannot be done with annotations. Annotation itself cannot be overridden. Entity inherits all the mapping information from MappedSuperClass. There is only two annotations that can be used to redefine mappings inherited from mapped superClass:

  1. AttributeOverride to override column mappings and
  2. AssociationOverride to override join columns / table.

Neither of them helps with GeneratedValue.

Mikko Maunu
  • 41,366
  • 10
  • 132
  • 135
4

With EclipseLink, you can use a Customizer. DescriptorCustomizer interface defines a way to customize all the information about a jpa descriptor (aka a persistent entity).

public class SequenceCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        descriptor.setSequenceNumberName(descriptor.getTableName());
    }
}

and in your mapped superclass:

@MappedSuperclass
@Customizer(SequenceCustomizer.class)
public abstract class AbstractEntity implements Serializable {
    ...
}
Hein Blöd
  • 1,553
  • 1
  • 18
  • 25
4

I'm writing this as it gets too unreadable as the comment on the accepted answer:

I have a BaseEntity that every other Entity inherits from:

BaseEntity.java:

@MappedSuperclass
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
    private Long id;

I then have two Entities User and Order that both inherit from BaseEntity whilst also having the @SequenceGenerator annotation:

User.java:

@SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_USER", allocationSize = 1)
public class User extends BaseEntity { ... }

Order.java:

@SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ORDER", allocationSize = 1)
public class Order extends BaseEntity { ... }

It works on H2 at least with 2 Sequences SEQ_USER and SEQ_ORDERS:

select SEQ_USER.nextval from dual;
select SEQ_ORDERS.nextval from dual;
Jonas Gröger
  • 1,558
  • 2
  • 21
  • 35
  • 2
    It works for multiple inherited entities, because Hibernate 5.18.3++ is tolerant by default. But you get warnings during startup: `org.hibernate.boot.internal.InFlightMetadataCollectorImpl - HHH000069: Duplicate generator name SEQ_ID`. See also https://hibernate.atlassian.net/browse/HHH-12454. If you get annoyed by the warnings, have a look at: https://stackoverflow.com/questions/5257921/#5258090 – leo Dec 17 '20 at 17:04