Невозможно использовать создание ключа столбца идентификаторов с <union-subclass> (TABLE_PER_CLASS)

97

com.something.SuperClass:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class SuperClass implements Serializable {
    private static final long serialVersionUID = -695503064509648117L;

    long confirmationCode;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // Causes exception!!!
    public long getConfirmationCode() {
        return confirmationCode;
    }

    public void setConfirmationCode(long confirmationCode) {
        this.confirmationCode = confirmationCode;
    }
}

com.something.SubClass:

@Entity
public abstract class Subclass extends SuperClass {
    private static final long serialVersionUID = 8623159397061057722L;

    String name;

    @Column(nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Дает мне это исключение:

Caused by: org.hibernate.MappingException: Cannot use identity column key
generation with <union-subclass> mapping for: com.something.SuperClass

Какой для меня самый лучший и удобный способ сгенерировать идентификаторы? Я не хочу менять свою стратегию наследования.

Мартейн Питерс
источник

Ответы:

232

Проблема здесь в том, что вы смешиваете наследование «таблица на класс» и GenerationType.Auto. Рассмотрим столбец идентичности в MsSQL. Он основан на столбцах. В стратегии «таблица на класс» вы используете одну таблицу на класс, и каждая из них имеет идентификатор.

Пытаться:

@GeneratedValue(strategy = GenerationType.TABLE)

Zoidbeck
источник
2
Идеальное решение. Даже на форумах Hibernate, похоже, не было этого решения, и они обсуждали
Spring Monkey
1
Эта проблема связана только с MySql или его обычным делом, когда я смотрю одно из видео для подхода Table per class, и он отлично работал в том случае, когда использовался postgres
Prashant
1
Я столкнулся с этим недавно при тестировании приложения Dropwizard. В моем случае я решил это, убедившись, что используются те же параметры конфигурации, что и DW для создания фабрики сеансов. Я почти уверен, что установка для свойства "hibernate.id.new_generator_mappings" значения true - вот что исправлено. Это DW 0.7.0, Hibernate 4.3.1, DB - H2.
sfitts
1
Работает отлично. Однако настоятельно рекомендуется не отдавать предпочтение стратегии генерации идентификаторов «ТАБЛИЦА», поскольку она запускает множество запросов (выбор, вставка и обновление) и поддерживает блокировки для генерации уникальных значений для первичного ключа. Итак, что было бы альтернативным решением этой проблемы, если бы у нас был довольно большой сценарий наследования? Это, безусловно, сильно повлияет на производительность.
MAC
8

Интересно, связана ли это с конкретной проблемой диалекта базы данных, поскольку, просмотрев учебник на YouTube с PostgreSQL в качестве базовой базы данных, я увидел, что создатель видео успешно запустил приложение с @GeneratedValue по умолчанию. В моем случае (базовая база данных - MySQL) мне пришлось изменить стратегию @GeneratedValue на GenerationType.TABLE точно так, как предлагает zoidbeck.

Вот видео: https://www.youtube.com/watch?v=qIdM4KQOtH8

скиабокс
источник
Postgres может выполнять наследование, поэтому вы можете быть правы в том, что это зависит от базы данных: postgresql.org/docs/8.1/static/ddl-inherit.html Видео не объясняет (или я пропустил его), как создается схема. Так что, возможно, диалект NHibernate postgres может сделать это сам по себе, или вместо этого вам нужно добавить «НАСЛЕДОВАНИЕ» вручную. На самом деле я не могу сказать.
zoidbeck
6
В PostgreSQL по умолчанию используется Hibernate GenerationType.SEQUENCE. Поэтому там он работает автоматически. Это не имеет абсолютно ничего общего с PostgreSQL INHERITS.
Хеннинг
Я использовал тот же учебник, и использование @Generated вызывало проблему, поскольку я использую MySql. Потратил много времени на отладку, пока не увидел этот пост
Дин Джон
5

Согласен с ответом Зойдбека. Вам необходимо изменить стратегию на:

@GeneratedValue(strategy = GenerationType.TABLE)

Но это еще не все, вам нужно создать новую таблицу, которая будет содержать последовательность первичных ключей вашей абстрактной таблицы. Измените свое сопоставление на

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "ConfirmationCodeGenerator")
@TableGenerator(table = "SEQUENCES", name = "ConfirmationCodeGenerator")
public long getConfirmationCode() {
   return confirmationCode;
}

И новая таблица в базе данных должна выглядеть следующим образом: введите описание изображения здесь

Когда вы запускаете свое приложение, Hibernate вставит строку, в которой sequence_nameбудет имя объекта ( SuperClassв этом примере), а sequence_next_hi_valueзначение будет автоматически увеличиваться и использоваться для новых записей всех реализующих таблиц подклассов.

Гонди
источник
2

В нашем случае мы используем базу данных PostreSQL для разработки и производства и базу данных hsqldb в памяти для тестов. В обоих случаях мы используем последовательность для генерации идентификатора. По-видимому, по GenerationType.AUTOумолчанию SEQUENCEдля postgres, но не удалось в наших локальных тестах (по умолчанию должно быть что-то другое для hsqldb).

Итак, решение, которое сработало для нас, явно использует GenerationType.SEQUENCE.

Райан Уоллс
источник
1

вы можете использовать @MappedSuperclass для наследования

Leimbag
источник
0

Между MySQL и PostgreSQL существует соответствие стандарту SQL. PostgreSQL Postgres хорошо понимает подмножество SQL92 / 99 плюс некоторые объектно-ориентированные функции для этих подмножеств. Postgres способен обрабатывать сложные подпрограммы и правила, такие как декларативные SQL-запросы, подзапросы, представления, многопользовательская поддержка, транзакции, оптимизация запросов, наследование и массивы. Не поддерживает выбор данных из разных баз данных.

MySQL MySQL использует SQL92 как основу. Работает на бесчисленных платформах. Mysql может создавать запросы, которые могут объединять таблицы из разных баз данных. Поддерживает как левое, так и правое внешнее объединение с использованием синтаксиса ANSI и ODBC. Начиная с MySQL 4.1, начиная с этого выпуска, MySQL будет обрабатывать подзапросы. Просмотры поддерживаются начиная с версии 5.

Для подробного описания посетите. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html

Coderac
источник
Пожалуйста, не расстраивайтесь по этому поводу, но я думаю, что сравнение MySQL и PostgreSQL не имеет отношения к теме (хотя значения по умолчанию Hibernate для них разные).
мртс