Não é possível usar a geração de chave de coluna de identidade com <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;
    }
}

Me dá esta exceção:

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

Qual é a melhor e mais conveniente maneira de gerar os IDs? Não quero mudar minha estratégia de herança.

Martijn Pieters
fonte

Respostas:

229

O problema aqui é que você mistura herança "tabela por classe" e GenerationType.Auto. Considere uma coluna de identidade em MsSQL. É baseado em colunas. Em uma estratégia "tabela por classe", você usa uma tabela por classe e cada uma tem um ID.

Experimentar:

@GeneratedValue(strategy = GenerationType.TABLE)

Zoidbeck
fonte
2
Solução perfeita. Mesmo os fóruns do Hibernate não pareciam ter essa solução, e eles estavam circulando
Spring Monkey
1
Este problema é apenas com o MySql ou é normal quando eu assisto um de um vídeo para a abordagem Tabela por classe e estava funcionando bem quando o postgres foi usado
Prashant
1
Corri para isso recentemente ao testar um aplicativo Dropwizard. No meu caso, resolvi isso certificando-me de usar as mesmas opções de configuração usadas pelo DW para criar a fábrica de sessão. Tenho certeza de que definir a propriedade "hibernate.id.new_generator_mappings" como true é o que corrigiu. Este é DW 0.7.0, Hibernate 4.3.1, DB era H2.
sfitts
1
Funciona perfeitamente. No entanto, é altamente recomendado não preferir usar a estratégia de geração de id 'TABLE', pois ela dispara muitas consultas (selecionar, inserir e atualizar) e mantém bloqueios para gerar valores únicos para a chave primária. Então, qual seria uma solução alternativa para isso se tivermos um cenário de herança meio grande? Certamente terá um grande impacto no desempenho.
MAC
8

Eu me pergunto se este é um problema específico de dialeto de banco de dados, já que assistindo a um tutorial do youtube com PostgreSQL como o banco de dados subjacente, vi que o criador do vídeo executou com sucesso um aplicativo com o @GeneratedValue padrão. No meu caso (o banco de dados subjacente é o MySQL), tive que modificar a estratégia @GeneratedValue para GenerationType.TABLE exatamente como o zoidbeck propõe.

Aqui está o vídeo: https://www.youtube.com/watch?v=qIdM4KQOtH8

skiabox
fonte
Postgres é capaz de fazer herança, então você pode estar certo de que isso é específico do banco de dados: postgresql.org/docs/8.1/static/ddl-inherit.html O vídeo não explica (ou não percebi) como o esquema é gerado. Portanto, talvez o dialeto postgres do NHibernate seja capaz de fazer isso por conta própria ou, em vez disso, você terá que adicionar 'INHERITS' manualmente. Na verdade, eu não posso dizer.
zoidbeck de
6
No PostgreSQL, o padrão do Hibernate é o uso GenerationType.SEQUENCE. É por isso que funciona automaticamente lá. Não tem absolutamente nada a ver com PostgreSQLs INHERITS.
Henning,
Tenho usado o mesmo tutorial e o uso de @Generated estava causando problemas, pois estou usando o MySql. Passei muito tempo depurando até ver este post
Deen John
5

Concordo com a resposta de zoidbeck. Você precisa mudar a estratégia para:

@GeneratedValue(strategy = GenerationType.TABLE)

Mas isso não é tudo, você precisa criar uma nova tabela, que conterá a sequência de chaves primárias da tabela do seu resumo. Modifique seu mapeamento para

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

E uma nova tabela no banco de dados deve ter a seguinte aparência: insira a descrição da imagem aqui

Quando você executa sua aplicação, o Hibernate irá inserir uma linha onde sequence_nameestará o nome da entidade ( SuperClassneste exemplo) e o sequence_next_hi_valuevalor será automaticamente incrementado e usado para novos registros de todas as tabelas de implementação das subclasses.

Gondy
fonte
2

Em nosso caso, usamos um banco de dados PostreSQL para desenvolvimento e produção e um banco de dados hsqldb na memória para testes. Estamos usando uma sequência em ambos os casos para gerar um id. Aparentemente, o GenerationType.AUTOpadrão é SEQUENCEpara postgres, mas falhou em nossos testes locais (deve usar outro padrão para hsqldb).

Portanto, a solução que funcionou para nós, use explicitamente GenerationType.SEQUENCE.

Ryan Walls
fonte
1

você pode usar @MappedSuperclass para herança

leimbag
fonte
0

Existe um padrão de conformidade SQL entre MySQL e PostgreSQL. PostgreSQL Postgres entende um bom subconjunto do SQL92 / 99 além de alguns recursos orientados a objetos para esses subconjuntos. Postgres é capaz de lidar com rotinas e regras complexas como consultas SQL declarativas, subconsultas, visualizações, suporte multiusuário, transações, otimização de consultas, herança e matrizes. Não suporta a seleção de dados em bancos de dados diferentes.

MySQL MySQL usa SQL92 como base. Funciona em inúmeras plataformas. Mysql pode construir consultas que podem unir tabelas de bancos de dados diferentes. Suporta junções externas esquerda e direita usando a sintaxe ANSI e ODBC. A partir do MySQL 4.1 a partir dessa versão, o MySQL tratará de subconsultas. Exibições suportadas a partir da versão 5.

Para uma descrição detalhada, visite. http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html

Coderac
fonte
Não se sinta mal com isso, mas acho que a comparação do MySQL e do PostgreSQL é irrelevante para o tópico (embora os padrões do Hibernate sejam diferentes para eles).
mrts de