7
respostas

Como utilizar @MappedSuperclass @Id com @Sequence Individual - hibernate oracle

Preciso solucionar uma questão de utilizar herança e sequences com hibernate e Oracle.

Estou utilizando Maven com: hibernate-core 5.1.5.Final hibernate-entitymanager 5.1.5.Final hibernate-validator 5.1.3.Final eclipselink 2.6.5 ojdbc6 11.2.0.4 javax.persistence 2.1.1 hibernate-jpa-2.1-api 1.0.0.Final

Tenho minha EntidadeDominio, no qual todas as classes extendem.

EntidadeDominio:

 @MappedSuperclass
public class EntidadeDominio implements IEntidade, Serializable {

    private static final long serialVersionUID = -5377726703339445533L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator = "SQ")
    private Integer id;
//Getter e Setters omitidos
}

Exemplo de classe: Email

@Entity
@Table(name = "EMAIL")
@AttributeOverride(name = "id", column = @Column(name = "COD_EMAIL"))
@SequenceGenerator(name="SQ", sequenceName = "SEQ_EMAIL", allocationSize = 1)
public class EmailEnvio extends EntidadeDominio{  
...
}

Cada entidade utiliza uma sequence diferente, pois o Banco é oracle e ele que ficará responsável por gerar esse sequence (regra de negócio).

Fiz varias buscas pela internet onde todas apresentavam o mesmo código que coloquei, porém apenas recebo o erro de "org.hibernate.AnnotationException: Unknown Id.generator: SQ" .

Tem alguma outra maneira de utilizar essas anotações?

@GeneratedValue(strategy = GenerationType.SEQUENCE ,generator = "SQ")

@SequenceGenerator(name="SQ", sequenceName = "SEQ_EMAIL", allocationSize = 1)

Ou estou utilizando as bibliotecas erradas? Já tentei várias mudanças no código mas não consegui resolver, não tenho muita experiencia com hibernate + oracle.

Desde já agradeço a ajuda!

7 respostas

Opa, nunca configurei com a @MappedSuperClass... Você já experimentou trazer o atributo id para a classe filha? Meu chute é que deixar o id referenciando uma sequence que não está definida na própria classe está dando ruim.

E dando uma opinião que eu que não foi pedida :). Essa classe mãe que só tem um id, no médio/longo prazo é uma cilada. Você ta gastando a herança para herdar um atributo... Criar um atributo na classe leva menos de 10 segundos.

Então ela possui outros atributos que são utilizados em todas as classes. Implemento essa EntidadeDominio por causa dos padrões que utilizo no projeto e que funciona muito bem.

Já tendei colocar individualmente o atributo id em cada classe filha, dá certo porém fica solicitando que a classe pai também tenha o @Id. Coloquei o @id nas duas classes dai o hibernate interpreta como se eu quisesse colocar chaves composta nas classes, o que não é o que quero.

EntidadeDominio

@MappedSuperclass
public class EntidadeDominio implements IEntidade, Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ")
    private Integer idEntidade;
//Getter e Setters e outros atributos omitidos

Classe Email

@Entity
@Table(name = "EMAIL")
public class Email extends EntidadeDominio {

    @Id
    @Column(name = "COD_EMAIL")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_EMAIL")
    @SequenceGenerator(name = "SEQ_EMAIL", sequenceName = "SEQ_EMAIL", allocationSize = 1)
    private Integer Id;

.... demais atributos e getters e setters omitidos
}

Porém dessa maneira creio que fica muita repetição de código de modo desnecessário, pois toda classe possui id logo poderia ficar na minha classe pai. Não encontro no hibernate como fazer isso com SEQUENCE, pois com increment ele vai normalmente.

Com implementação executa normalmente:


@MappedSuperclass
public class EntidadeDominio implements IEntidade, Serializable {

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")    
    @Column(nullable = false, insertable = true, updatable = true)
    public Integer id;

...
}

Porém como regra de negocio os Ids devem ser gerado pelo banco Oracle com sequence.

E se tirar o mappedsupperclass? Estou realmente em dúvida se precisa dele :). Mas também nunca utilizei, por isso que estou testando as possibilidades.

Sem o @MappedSuperClass as entidades devem implementar seu próprio @Id. E que ocasiona o erro:

org.hibernate.AnnotationException: No identifier specified for entity: com.projart.*

Todas as entidade que extendem EntidadeDominio acabam não herdando o atributo que contem o @Id. O que não funciona no meu caso.

Cheguei em algum lugar utilizando:

@MappedSuperclass
public class EntidadeDominio implements IEntidade, Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator = "SQ")
    @SequenceGenerator(name="SQ", sequenceName="SQ", allocationSize = 1)
    private Integer id;
}

E classe Email:

@Entity
@Table(name = "EMAIL")
@AttributeOverride(name = "id", column = @Column(name = "COD_EMAIL"))
@SequenceGenerator(name  = "SQ", sequenceName = "SEQ_EMAIL")
public class ModeloEmail extends EntidadeDominio {
//atributos e metodos
}

Porém ele não está utilizando a Sequence correta. Ao inves de usar há SEQ_EMAIL da classe Email, está utilizando SQ para todas as classes. Não tem nenhuma maneira de sobrescrever a anotação @SequenceGenerator?

Não, o name da sequence é global... Você realmente precisa ter sequences com names diferentes dentro do escopo. Olhando todos os lados minha sugestão é realmente ter os ids nas entidades específicas.

Codifiquei de modo a separar cada @Id.

Anotei a classe como Inheritance para realizar a herança.

EntidadeDominio

@Inheritance(strategy = InheritanceType.JOINED)
//@MappedSuperclass
public class EntidadeDominio implements IEntidade, Serializable { ... }

Classe Enderecamento

@Entity
@Table(name = "ENDERECAMENTO")
public class Enderecamento extends EntidadeDominio {

    @Id
    @Column(name="COD_ENDERECAMENTO")
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_ENDERECAMENTO")
    @SequenceGenerator(name="SEQ_ENDERECAMENTO", sequenceName = "SEQ_ENDERECAMENTO", allocationSize = 1)
    private Integer Id;

//demais atributos e metodos omitidos ...

}

Porém está apresentando seguinte erro:

 java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [id] on this ManagedType [com.projart.model.Enderecamento]
    at org.hibernate.jpa.internal.metamodel.AbstractManagedType.checkNotNull(AbstractManagedType.java:128)
    at org.hibernate.jpa.internal.metamodel.AbstractManagedType.getAttribute(AbstractManagedType.java:113)
    at org.hibernate.jpa.criteria.path.AbstractFromImpl.locateAttributeInternal(AbstractFromImpl.java:116)
    at org.hibernate.jpa.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:204)
    at org.hibernate.jpa.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:177)
    at com.projart.core.dao.imp.EnderecamentoDAO.findByCriterios(EnderecamentoDAO.java:139)
    at com.projart.view.ProcessarEnderecamento.getEnderecamento(ProcessarEnderecamento.java:38)
    at com.projart.view.Servlet.<init>(Servlet.java:102)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1095)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:817)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:135)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)