MappedSuperclass — изменить SequenceGenerator в подклассе

Я использую JPA2 с Hibernate и пытаюсь ввести общий базовый класс для своих сущностей. Пока это выглядит так:

@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;
    }
}

Однако для каждой таблицы существует последовательность $entityname_seq, которую я хочу использовать в качестве генератора последовательности. Как я могу установить это из своего подкласса? Я думаю, мне нужно переопределить @GeneratedValue и создать новый SequenceGenerator с @SequenceGenerator.


person atamanroman    schedule 21.12.2011    source источник


Ответы (4)


Да, это возможно. Вы можете переопределить имя генератора по умолчанию с помощью аннотации @SequenceGenerator.

  • Базовый класс
    @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;
        }
    }
  • Последовательность (SQL)

    create sequence role_seq;
  • Производный класс

    @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;
        }   
    }
  • Этот подход отлично работал в Hibernate 4.1.x, но не в EclipseLink 2.x.

изменить

  • Судя по комментарию, он работает с EclipseLink 2.6.1-RC1.
person rbento    schedule 28.08.2012
comment
Я тестировал EclipseLink 2.6.1-RC1, и это тоже сработало. - person leocborges; 11.08.2015
comment
Это прекрасные новости. Спасибо! Я собираюсь отредактировать ответ. - person rbento; 11.08.2015
comment
Кроме того, для всех подклассов должен быть определен @SequenceGenerator, иначе при сопоставлении будут выданы ошибки. - person Stephen Senkomago Musoke; 29.08.2015
comment
Это неправильное решение. Это будет работать только до тех пор, пока у вас есть только один подкласс PersistentEntity. Допустим, вы создаете группу объектов, которая также расширяет PersistentEntity. Затем вы получите сообщение об ошибке, поскольку генератор последовательности default_gen определен дважды в одном и том же модуле сохранения состояния. (EclipseLink 2.6.2) - person peterh; 25.03.2016
comment
@peterh Пожалуйста, проверьте весь пост, посмотрите нижние строки. В то время, когда на него ответили, он работал с спящим режимом, но даже не работал с EclipseLink, и позже есть редактирование. Казалось, это решило проблему ОП, а также многих других пользователей. Мне жаль, что это не сработало для вас. Не стесняйтесь вносить свой вклад с вашим решением. - person rbento; 25.03.2016
comment
@рбенто. Дело принято. Да, я должен был сказать, что это решение больше не работает в современном мире и с последним EclipseLink. Может быть, он все еще нормально работает с Hibernate, не знаю. Я не сомневаюсь, что это работало в прошлом. Боюсь, я не нашел достойного решения с EclipseLink. - person peterh; 26.03.2016
comment
Действительно, как указано в JEE-7. Область действия имени генератора является глобальной для единицы сохраняемости (для всех типов генераторов). Таким образом, даже если в какой-то момент это работает с некоторыми реализациями, это не стандартное поведение. - person benjamin.donze; 11.05.2016
comment
В отличие от некоторых отмеченных здесь, у меня это работает с Spring Boot JPA и Hibernate. См. мой длинный ответ здесь: stackoverflow.com/a/58543347/488265 - person Jonas Gröger; 24.10.2019

В JPA это невозможно сделать с помощью аннотаций. Сама аннотация не может быть переопределена. Entity наследует всю информацию о сопоставлении от MappedSuperClass. Есть только две аннотации, которые можно использовать для переопределения сопоставлений, унаследованных от сопоставленного суперкласса:

  1. AttributeOverride для переопределения сопоставлений столбцов и
  2. AssociationOverride для переопределения столбцов/таблиц объединения.

Ни один из них не помогает с GeneratedValue.

person Mikko Maunu    schedule 17.07.2012

С EclipseLink вы можете использовать файл Customizer. DescriptorCustomizer определяет способ настройки всей информации об дескрипторе jpa (также известном как постоянный объект).

public class SequenceCustomizer implements DescriptorCustomizer {

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

и в вашем сопоставленном суперклассе:

@MappedSuperclass
@Customizer(SequenceCustomizer.class)
public abstract class AbstractEntity implements Serializable {
    ...
}
person Juan Francisco Montanaro    schedule 11.09.2015

Я пишу это, так как это становится слишком нечитаемым, как комментарий к принятому ответу:

У меня есть BaseEntity, от которого наследуется любая другая сущность:

Базеентити.java:

@MappedSuperclass
public abstract class BaseEntity {

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

Затем у меня есть две сущности User и Order, которые обе наследуются от BaseEntity, а также имеют аннотацию @SequenceGenerator:

Пользователь.java:

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

Заказ.java:

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

Он работает на H2 по крайней мере с 2 последовательностями SEQ_USER и SEQ_ORDERS:

select SEQ_USER.nextval from dual;
select SEQ_ORDERS.nextval from dual;
person Jonas Gröger    schedule 24.10.2019
comment
Это работает для нескольких унаследованных сущностей, потому что Hibernate 5.18.3++ по умолчанию терпим. Но при запуске вы получаете предупреждения: org.hibernate.boot.internal.InFlightMetadataCollectorImpl - HHH000069: Duplicate generator name SEQ_ID. См. также hibernate.atlassian.net/browse/HHH-12454. Если вас раздражают предупреждения, посмотрите: stackoverflow.com/questions/5257921/#5258090 - person leo; 17.12.2020