Nie można użyć generowania klucza kolumny tożsamości z <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;
    }
}

Daje mi ten wyjątek:

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

Jaki jest najlepszy i najwygodniejszy sposób generowania identyfikatorów? Nie chcę zmieniać mojej strategii dziedziczenia.

Martijn Pieters
źródło

Odpowiedzi:

232

Problem polega na tym, że łączysz dziedziczenie „tabela-na-klasę” i GenerationType.Auto. Rozważ kolumnę tożsamości w MsSQL. Jest oparty na kolumnach. W strategii „tabela-na-klasę” używasz jednej tabeli na klasę i każda z nich ma identyfikator.

Próbować:

@GeneratedValue(strategy = GenerationType.TABLE)

zoidbeck
źródło
2
Idealne rozwiązanie. Wydawało się, że nawet fora poświęcone Hibernate nie mają tego rozwiązania i poruszali się
Spring Monkey,
1
Czy ten problem dotyczy tylko MySql, czy jego regularnego, gdy oglądam jeden z filmów dotyczących podejścia Table per class i działał dobrze, gdy użyto postgres
Prashant
1
Natknąłem się na to niedawno podczas testowania aplikacji Dropwizard. W moim przypadku rozwiązałem to, upewniając się, że używam tych samych opcji konfiguracyjnych, które są używane przez DW do tworzenia fabryki sesji. Jestem prawie pewien, że ustawienie właściwości „hibernate.id.new_generator_mappings” na true jest tym, co to naprawiło. To jest DW 0.7.0, Hibernacja 4.3.1, DB to H2.
sfitts
1
Działa doskonale. Jednak zdecydowanie zaleca się, aby nie preferować strategii generowania identyfikatorów „TABELA”, ponieważ wyzwala ona wiele zapytań (wybieranie, wstawianie i aktualizowanie) oraz utrzymuje blokady w celu wygenerowania unikalnych wartości dla klucza podstawowego. Więc jakie byłoby alternatywne rozwiązanie tego problemu, gdybyśmy mieli jakiś duży scenariusz dziedziczenia? Z pewnością wpłynie to w dużym stopniu na wydajność.
MAC
8

Zastanawiam się, czy jest to problem specyficzny dla dialektu bazy danych, ponieważ oglądając samouczek YouTube z PostgreSQL jako bazową bazą danych, zobaczyłem, że twórca wideo pomyślnie uruchomił aplikację z domyślną @GeneratedValue. W moim przypadku (bazową bazą danych jest MySQL) musiałem zmodyfikować strategię @GeneratedValue na GenerationType.TABLE dokładnie tak, jak proponuje zoidbeck.

Oto wideo: https://www.youtube.com/watch?v=qIdM4KQOtH8

skiabox
źródło
Postgres może dziedziczyć, więc możesz mieć rację, że jest to specyficzne dla bazy danych: postgresql.org/docs/8.1/static/ddl-inherit.html Film nie wyjaśnia (lub przegapiłem), w jaki sposób generowany jest schemat. Więc może dialekt NHibernate postgres jest w stanie zrobić to samodzielnie lub zamiast tego musisz ręcznie dodać 'INHERITS'. Właściwie nie mogę powiedzieć.
zoidbeck
6
W PostgreSQL Hibernate domyślnie używa GenerationType.SEQUENCE. Dlatego działa tam automatycznie. Nie ma to absolutnie nic wspólnego z PostgreSQL INHERITS.
Henning,
Używałem tego samego samouczka i @Generated powodowało problem, ponieważ używam MySql. Spędziłem dużo czasu na debugowaniu, dopóki nie zobaczyłem tego postu
Deen John
5

Zgadzam się z odpowiedzią Zoidbecka. Musisz zmienić strategię na:

@GeneratedValue(strategy = GenerationType.TABLE)

Ale to nie wszystko, musisz utworzyć nową tabelę, która będzie przechowywać sekwencję kluczy podstawowych tabeli streszczenia. Zmodyfikuj mapowanie do

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

A nowa tabela w bazie danych powinna wyglądać następująco: wprowadź opis obrazu tutaj

Po uruchomieniu aplikacji Hibernate wstawi wiersz, w którym sequence_namebędzie nazwa jednostki ( SuperClassw tym przykładzie), a sequence_next_hi_valuewartość zostanie automatycznie zwiększona i wykorzystana do nowych rekordów wszystkich implementujących tabel podklas.

Gondy
źródło
2

W naszym przypadku używamy bazy danych PostreSQL do tworzenia i produkcji oraz bazy danych hsqldb w pamięci do testów. W obu przypadkach używamy sekwencji do generowania identyfikatora. Wygląda na to, że GenerationType.AUTOdomyślnie jest to SEQUENCEpostgres, ale nie powiodło się w naszych lokalnych testach (musi być domyślnie ustawione na coś innego dla hsqldb).

Więc rozwiązanie, które działało dla nas, wyraźnie użyj GenerationType.SEQUENCE.

Ryan Walls
źródło
1

możesz użyć @MappedSuperclass do dziedziczenia

leimbag
źródło
0

Pomiędzy MySQL i PostgreSQL istnieje zgodność ze standardem SQL. PostgreSQL Postgres rozumie dobry podzbiór SQL92 / 99 oraz kilka funkcji obiektowych w tych podzbiorach. Postgres jest w stanie obsługiwać złożone procedury i reguły jako deklaratywne zapytania SQL, podzapytania, widoki, obsługę wielu użytkowników, transakcje, optymalizację zapytań, dziedziczenie i tablice. Nie obsługuje wybierania danych z różnych baz danych.

MySQL MySQL używa SQL92 jako podstawy. Działa na niezliczonych platformach. MySQL może konstruować zapytania, które mogą łączyć tabele z różnych baz danych. Obsługuje lewe i prawe sprzężenia zewnętrzne przy użyciu składni ANSI i ODBC. Począwszy od MySQL 4.1 od tego wydania, MySQL będzie obsługiwał podzapytania. Widoki obsługiwane od wersji 5.

Szczegółowy opis można znaleźć na stronie. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html

Coderac
źródło
Proszę nie przejmować się tym, ale myślę, że porównanie MySQL i PostgreSQL jest nieistotne w tym temacie (nawet jeśli domyślne ustawienia Hibernacji są dla nich inne).
kończy się