Die Generierung von Identitätsspaltenschlüsseln mit <union-subclass> (TABLE_PER_CLASS) kann nicht verwendet werden.

94

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

Gibt mir diese Ausnahme:

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

Was ist der beste und bequemste Weg für mich, die IDs zu generieren? Ich möchte meine Vererbungsstrategie nicht ändern.

Martijn Pieters
quelle

Antworten:

228

Das Problem hierbei ist, dass Sie die Vererbung "Tabelle pro Klasse" und mischen GenerationType.Auto. Betrachten Sie eine Identitätsspalte in MsSQL. Es ist spaltenbasiert. In einer "Tabelle pro Klasse" -Strategie verwenden Sie eine Tabelle pro Klasse und jede hat eine ID.

Versuchen:

@GeneratedValue(strategy = GenerationType.TABLE)

Zoidbeck
quelle
2
Perfekte Lösung. Sogar Hibernate-Foren schienen diese Lösung nicht zu haben, und sie gingen um das Thema forum.hibernate.org/…
Spring Monkey
1
Ist dieses Problem nur mit MySQL oder ist es regulär, da ich mir eines der Videos für den Ansatz "Tabelle pro Klasse" ansehe und es gut funktioniert hat, dass Postgres verwendet wurde
Prashant
1
Ich bin kürzlich beim Testen einer Dropwizard-Anwendung darauf gestoßen. In meinem Fall habe ich mich darum gekümmert, indem ich sichergestellt habe, dass die gleichen Konfigurationsoptionen verwendet werden, die DW zum Erstellen der Sitzungsfactory verwendet. Ich bin mir ziemlich sicher, dass das Setzen der Eigenschaft "hibernate.id.new_generator_mappings" auf true das Problem behoben hat. Dies ist DW 0.7.0, Hibernate 4.3.1, DB war H2.
sfitts
1
Es funktioniert perfekt. Es wird jedoch dringend empfohlen, die ID-Generierungsstrategie 'TABLE' nicht zu bevorzugen, da sie viele Abfragen auslöst (auswählen, einfügen und aktualisieren) und Sperren verwaltet, um eindeutige Werte für den Primärschlüssel zu generieren. Was wäre also eine alternative Lösung dafür, wenn wir ein ziemlich großes Vererbungsszenario haben? Dies wird sich sicherlich stark auf die Leistung auswirken.
MAC
8

Ich frage mich, ob dies ein datenbankdialektspezifisches Problem ist, da ich beim Betrachten eines YouTube-Tutorials mit PostgreSQL als zugrunde liegender Datenbank festgestellt habe, dass der Ersteller des Videos erfolgreich eine App mit dem Standardwert @GeneratedValue ausführt. In meinem Fall (die zugrunde liegende Datenbank ist MySQL) musste ich die @ GeneratedValue-Strategie genau wie von zoidbeck vorgeschlagen in GenerationType.TABLE ändern.

Hier ist das Video: https://www.youtube.com/watch?v=qIdM4KQOtH8

Skiabox
quelle
Postgres kann Vererbung durchführen, sodass Sie möglicherweise Recht haben, dass dies datenbankspezifisch ist: postgresql.org/docs/8.1/static/ddl-inherit.html Das Video erklärt nicht (oder ich habe es verpasst), wie das Schema generiert wird. Vielleicht kann der Postgres-Dialekt von NHibernate dies selbst tun, oder Sie müssen stattdessen die 'ERBEN' manuell hinzufügen. Eigentlich kann ich nicht sagen.
Zoidbeck
6
Unter PostgreSQL wird standardmäßig der Ruhezustand verwendet GenerationType.SEQUENCE. Deshalb funktioniert es dort automatisch. Es hat absolut nichts mit PostgreSQLs zu tun INHERITS.
Henning
Ich habe das gleiche Tutorial verwendet und die Verwendung von @Generated verursachte Probleme, da ich MySql verwende. Ich habe viel Zeit mit dem Debuggen verbracht, bis ich diesen Beitrag gesehen habe
Deen John
5

Stimmen Sie der Antwort von Zoidbeck zu. Sie müssen die Strategie ändern in:

@GeneratedValue(strategy = GenerationType.TABLE)

Aber das ist noch nicht alles. Sie müssen eine neue Tabelle erstellen, die die Primärschlüsselfolge der Tabelle Ihres Abstracts enthält. Ändern Sie Ihre Zuordnung zu

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

Eine neue Tabelle in der Datenbank sollte folgendermaßen aussehen: Geben Sie hier die Bildbeschreibung ein

Wenn Sie Ihre Anwendung ausgeführt haben, fügt Hibernate eine Zeile ein, in sequence_nameder der Entitätsname ( SuperClassin diesem Beispiel) angegeben ist. Der sequence_next_hi_valueWert wird automatisch erhöht und für neue Datensätze aller Tabellen der implementierenden Unterklassen verwendet.

Gondy
quelle
2

In unserem Fall verwenden wir eine PostreSQL-Datenbank für Entwicklung und Produktion und eine speicherinterne hsqldb-Datenbank für Tests. In beiden Fällen verwenden wir eine Sequenz, um eine ID zu generieren. Anscheinend GenerationType.AUTOstandardmäßig SEQUENCEfür Postgres, aber in unseren lokalen Tests fehlgeschlagen (muss für hsqldb standardmäßig etwas anderes sein).

Also die Lösung, die für uns funktioniert hat, explizit verwenden GenerationType.SEQUENCE.

Ryan Walls
quelle
1

Sie können @MappedSuperclass für die Vererbung verwenden

Leimbag
quelle
0

Zwischen MySQL und PostgreSQL besteht eine SQL-Standardkonformität. PostgreSQL Postgres versteht eine gute Teilmenge von SQL92 / 99 sowie einige objektorientierte Funktionen dieser Teilmengen. Postgres kann komplexe Routinen und Regeln als deklarative SQL-Abfragen, Unterabfragen, Ansichten, Mehrbenutzerunterstützung, Transaktionen, Abfrageoptimierung, Vererbung und Arrays verarbeiten. Unterstützt nicht die Auswahl von Daten in verschiedenen Datenbanken.

MySQL MySQL verwendet SQL92 als Grundlage. Läuft auf unzähligen Plattformen. MySQL kann Abfragen erstellen, die Tabellen aus verschiedenen Datenbanken verknüpfen können. Unterstützt sowohl linke als auch rechte äußere Verknüpfungen mit ANSI- und ODBC-Syntax. Ab MySQL 4.1 verarbeitet MySQL Unterabfragen. Ab Version 5 unterstützte Ansichten.

Für eine detaillierte Beschreibung besuchen Sie bitte. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html

Coderac
quelle
Bitte fühlen Sie sich nicht schlecht dabei, aber ich denke, dass der Vergleich von MySQL und PostgreSQL für das Thema irrelevant ist (obwohl die Standardeinstellungen für den Ruhezustand für sie unterschiedlich sind).
Herr