Impossibile utilizzare la generazione della chiave della colonna di identità con <union-subclass> (TABLE_PER_CLASS)


95

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

Mi dà questa eccezione:

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

Qual è il modo migliore e più conveniente per generare gli ID? Non voglio cambiare la mia strategia di eredità.

Risposte:


229

Il problema qui è che mescoli l'ereditarietà "tabella per classe" e GenerationType.Auto. Considera una colonna Identity in MsSQL. È basato su colonne. In una strategia "tabella per classe" si utilizza una tabella per classe e ognuna ha un ID.

Provare:

@GeneratedValue(strategy = GenerationType.TABLE)


2
Soluzione perfetta. Persino i forum di Hibernate non sembravano avere questa soluzione, e stavano girando intorno all'argomento forum.hibernate.org/…
Spring Monkey

1
Questo problema riguarda solo MySql o è normale mentre guardo uno di un video per l'approccio Table per class e funzionava bene quando è stato utilizzato postgres
Prashant

1
Mi sono imbattuto in questo di recente durante il test di un'applicazione Dropwizard. Nel mio caso ho risolto il problema assicurandomi di utilizzare le stesse opzioni di configurazione utilizzate da DW per creare la session factory. Sono abbastanza sicuro che l'impostazione della proprietà "hibernate.id.new_generator_mappings" su true sia ciò che l'ha risolto. Questo è DW 0.7.0, Hibernate 4.3.1, DB era H2.
sfitts

1
Funziona perfettamente. Tuttavia, si consiglia vivamente di non preferire l'utilizzo della strategia di generazione dell'ID "TABELLA" poiché attiva molte query (selezione, inserimento e aggiornamento) e mantiene i blocchi per generare valori univoci per la chiave primaria. Quindi quale sarebbe una soluzione alternativa a questo se avessimo un grande scenario di ereditarietà? Sicuramente avrà un grande impatto sulle prestazioni.
MAC

8

Mi chiedo se questo sia un problema specifico del dialetto del database, poiché guardando un tutorial di YouTube con PostgreSQL come database sottostante ho visto che il creatore del video ha eseguito con successo un'app con il valore predefinito @GeneratedValue. Nel mio caso (il database sottostante è MySQL) ho dovuto modificare la strategia @GeneratedValue in GenerationType.TABLE esattamente come propone zoidbeck.

Ecco il video: https://www.youtube.com/watch?v=qIdM4KQOtH8


Postgres è in grado di eseguire l'ereditarietà, quindi potresti avere ragione sul fatto che questo è specifico del database: postgresql.org/docs/8.1/static/ddl-inherit.html Il video non spiega (o mi è mancato) come viene generato lo schema. Quindi forse il dialetto NHibernate postgres è in grado di farlo da solo o invece devi aggiungere manualmente "INHERITS". In realtà non posso dirlo.
zoidbeck

6
In PostgreSQL, Hibernate utilizza per impostazione predefinita GenerationType.SEQUENCE. Ecco perché funziona automaticamente lì. Non ha assolutamente nulla a che fare con PostgreSQL INHERITS.
Henning

Ho utilizzato lo stesso tutorial e l'utilizzo di @Generated stava causando problemi poiché utilizzo MySql. Ho trascorso molto tempo a eseguire il debug fino a quando non ho visto questo post
Deen John

5

D'accordo con la risposta di zoidbeck. Devi cambiare strategia per:

@GeneratedValue(strategy = GenerationType.TABLE)

Ma non è tutto, è necessario creare una nuova tabella, ciò che conterrà la sequenza di chiavi primarie della tabella dell'abstract. Modifica la tua mappatura in

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

E una nuova tabella nel database dovrebbe essere simile alla seguente: inserisci qui la descrizione dell'immagine

Quando si esegue l'applicazione, Hibernate inserirà una riga in cui sequence_namesarà il nome dell'entità ( SuperClassin questo esempio) e il sequence_next_hi_valuevalore verrà automaticamente incrementato e utilizzato per i nuovi record di tutte le tabelle delle sottoclassi di implementazione.


2

Nel nostro caso, utilizziamo un database PostreSQL per lo sviluppo e la produzione e un database hsqldb in memoria per i test. In entrambi i casi stiamo usando una sequenza per generare un id. Apparentemente il GenerationType.AUTOvalore predefinito è SEQUENCEper postgres, ma non è riuscito nei nostri test locali (deve essere impostato su qualcos'altro per hsqldb).

Quindi la soluzione che ha funzionato per noi, usa esplicitamente GenerationType.SEQUENCE.


1

puoi usare @MappedSuperclass per l'ereditarietà


0

Esiste uno standard di conformità SQL tra MySQL e PostgreSQL. PostgreSQL Postgres comprende un buon sottoinsieme di SQL92 / 99 più alcune funzionalità orientate agli oggetti per questi sottoinsiemi. Postgres è in grado di gestire routine e regole complesse come query SQL dichiarative, sottoquery, viste, supporto multiutente, transazioni, ottimizzazione delle query, ereditarietà e array. Non supporta la selezione di dati tra database diversi.

MySQL MySQL utilizza SQL92 come base. Funziona su innumerevoli piattaforme. Mysql può costruire query che possono unire tabelle da diversi database. Supporta i join esterni sinistro e destro utilizzando la sintassi ANSI e ODBC. A partire da MySQL 4.1 da quella versione in poi, MySQL gestirà le sottoquery. Visualizzazioni supportate dalla versione 5.

Per una descrizione dettagliata si prega di visitare. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html


Per favore, non sentirti male per questo, ma penso che il confronto tra MySQL e PostgreSQL sia irrilevante per l'argomento (anche se i valori predefiniti di Hibernate sono diversi per loro).
Sig.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.