Mostrando postagens com marcador Hibernate. Mostrar todas as postagens
Mostrando postagens com marcador Hibernate. Mostrar todas as postagens

terça-feira, 11 de setembro de 2007

Herança "simples" com Hibernate

Olá pessoas,

Hoje comentarei sobre mapeamento de herança com o Hibernate através de annotations.
Conforme documentações e exemplos que encontramos por ai, sabemos que existem 3 tipos de mapeamento de herança:
  • Joined - Usado quando quer criar uma tabela para a classe genérica e demais tabelas que derivam dela, por exemplo: Pessoa, Pessoa Física, Pessoa Jurídica. Neste caso teriam 3 tabelas.
  • Single Table - Usado quando quer criar uma única tabela para armazenar os dados. No caso da Pessoa, Pessoa Física, Pessoa Jurídica, teria uma única tabela com todas os atributos.
  • Table Per Class - Usado quando quer criar uma tabela para cada subclasse. No caso da Pessoa, Pessoa Física, Pessoa Jurídica, teriam duas tabelas: Pessoa Fisica e Pessoa Juridica, os atributos da classe Pessoa seriam replicados nas duas tabelas.
A questão é que para utilizar estes tipos de mapeamento de herança é necessário anotar a classe mais genérica com @Entiety, ou seja deve ser uma entidade gerenciada pelo hibernate. Se uma classe é uma Entiety, obrigatoriamente ela deve conter um atributo anotado com @Id.
Se for utilizar o mapeamento de herança do tipo Table Per Class, não é possível determinar o atributo anotado com @Id como @GeneratedValue do tipo AUTO ou IDENTITY. Em alguns casos isso é um problema, para explicar melhor vou citar um exemplo:

Uma classe abstrata Modelo possui alguns atributos incluindo um ID.
Uma classe concreta ModeloCorporativo deriva de Modelo e possui mais alguns atributos.
A nível de base de dados, a tabela do modelo corporativo deve possuir todos os atributos da classe modelo e mais os seus atributos. Dentre estes atributos, está o ID, este deve ser gerado automaticamente pelo banco (via sequence, via auto_increment, etc)

A primeira vista, parece que o melhor tipo de mapeamento para esta herança é usar TablePerClass, mas dessa forma o atributo ID da classe abstrata não poderia estar anotado com @GeneratedValue(stategy=GenerationType.AUTO), pois isso é uma regra do hibernate (inclusive citada na documentação do hibernate annotations).
Então para resolver esta situação a forma mais indicada seria criar uma classe abstrata Modelo e anota-la com @MappedSuperclass, Este tipo de mapeamento de herança (que nunca aparece nos exemplos comuns de herança) não exige que a classe seja anotada com @Entiety, ou seja, o hibernate vai saber que esta classe só vai servir para "embutir" os atributos na tabela representada pelas subclasses.

O código ficaria assim:
@MappedSuperclass
public abstract class Modelo {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

// outros atributos e getters e setters omitidos.
}

@Entity
public class ModeloCorporativo extends Modelo {
private String mascara;

// getters e setters omitidos
}

Desta forma a tabela ModeloCorporativo terá todos os atributos da classe Modelo e mais o seu atributo mascara. O importante é que o atributo ID herdado da classe Modelo pode ser anotado com @GeneratedValue(strategy=GenerationType.AUTO) e, de acordo com o banco de dados, terá seu id gerado automaticamente
Qualquer dúvida posta aí.
[]'s

terça-feira, 14 de agosto de 2007

"AutoRelacionamento" com Hibernate

Hoje tive que implementar o menu de uma aplicação que estou fazendo e precisava de uma classe que representasse uma tabela mais ou menos assim:

CREATE TABLE sis_menu (
id bigint(20) NOT NULL,
acao varchar(255) default NULL,
chave varchar(255) NOT NULL,
idMenuPai bigint(20) default NULL,
PRIMARY KEY (`id`),
KEY `fk_id_pai` (`idMenuPai`),
FOREIGN KEY (`idMenuPai`) REFERENCES `sis_menu` (`id`)
)

Ou seja, tinha que fazer um relacionamento da tabela sis_menu com ela mesma para ter uma hierarquia dos itens do menu.

Para isso escrevi a seguinte classe POJO com anotações do hibernate:

@Entity
@Table(name="sis_menu")
public class Menu {

@Id @GeneratedValue
private Long id;

@NotEmpty(message="menu.chaveEmpty")
private String chave;

private String acao;

@OneToMany(mappedBy="menuPai", fetch=FetchType.LAZY)
@Cascade(CascadeType.ALL)
private List\ subMenus;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="idMenuPai", insertable=true, updatable=true)
@Fetch(FetchMode.JOIN)
@Cascade(CascadeType.SAVE_UPDATE)
private Menu menuPai;

// getters e setters
}

Não cheguei nesta solução sozinho, o que fiz foi googlear até achar isso. Acabei encontrando um PDF em portugues muito bom que ensina como utilizar mapeamentos no hibernate. Segue o link:
ftp://users.dca.ufrn.br/hibernate_anotacoes/T03_Relacionamentos_1.pdf