A Java Persistence API é sensacional. No começo eu não ia com a cara dela, mas agora ela está muito madura e funciona redondinha que nem um coco. Eu tenho uma grande dificuldade com ela, as anotações para Join e para objetos que não são uma tabela. Toda vez que preciso utilizar, busco algo que já fiz, ou tenho que sair vasculhando a WEB. Então vou colocar aqui meu personal guia de referencia JPA! Se eu conseguir superar a preguiça, coloco também um pouquinho das anotações mais básicas, para os newbies.
Uma conceito muito simples, porém muito importante na hora de fazer os relacionamentos é saber se o mesmo será Unidirecional ou Bidirecional.
Unidirecional
Apenas uma dos lados(classe) conhecerá a outra.
Bidirecional
@OneToOne – Unidirecional
Veremos abaixo o relacionamento 1 para 1(@OneToOne) unidirecional:
@Entity public class Pessoa{ @Id @GeneratedValue private int id; private String nome; @OneToOne @JoinColumn(name="id_celular") private Celular celularX; } @Entity public class Celular { @Id @GeneratedValue private int id; private int numero; }
@OneToOne – Bidirecional
Chamei a propriedade celular da classe Pessoa de celularX, para ficar bem claro agora que na propriedade mappedBy da anotação OneToOne o valor do campo é o nome da Propriedade, e não o nome do campo na Tabela.
@Entity public class Pessoa{ @Id @GeneratedValue private int id; private String nome; @OneToOne @JoinColumn(name="id_celular") private Celular celularX; } @Entity public class Celular { @Id @GeneratedValue privateint id; privateint numero; @OneToOne(mappedBy="celularX") private Pessoa pessoa; }
Para lembrar
@JoinColumn – Coluna a ser utilizado no Join(Ligação) entre as tabelas, refere-se a entidade, classe, e consequentemente à tabela onde a anotação foi feita.
(mappedBy=””) – Tradução : Mapeado Por, ou seja mapeado por alguma outra coisa. Logo refere-se a entidade, classe, e consequentemente tabela que está abaixo da anotação que contém a propriedade de anotação mappedBy. O valor do mappedBy é o nome da propriedade na outra entidade(classe), que se relaciona com a entidade(classe) atual, onde o mappedBy está.
OneToMany e ManyToOne
ManyToOne
- Utilizaremos novamente a anotação @JoinColumn para definir quem será o dono do relacionamento.
- O lado do relacionamento que tiver a anotação @ManyToOne será sempre dominante.
- Não existe a opção de utilizar mappedBy dentro da anotação @ManyToOne.
@Entity public class Ligacao{ @Id @GeneratedValue private int id; @ManyToOne @JoinColumn(name = "id_celular") private Celular celular; private long duracao; }
OneToMany
- Utilizamos a anotação @OneToMany sempre sobre uma coleção.
- Utilizamos o mappedBy para indicar que esse relacionamento NÃO é o lado dominante.
@Entity public class Celular { @Id @GeneratedValue private int id; private int numero; @OneToOne(mappedBy="celularX") private Pessoa pessoa; @OneToMany(mappedBy = "celular") private List listaLigacoes; }
Não existe relacionamento automático
Para que um relacionamento bidirecional funcione corretamente é necessário fazer o set na propriedade dos dois objetos, e não apenas um e assumir que alguém fará o reverso para você automaticamente. Exemplo:
Pessoa pessoa = new Pessoa(); Celular celular = new Celular(); pessoa.setCelularX(celular); celular.setPessoa(pessoa); entityManager.persist();
Chave Primária
@Id
Para definição de Ids de tabela no banco temos duas principais formas. Atualmente o Oracle e o Postgres trabalham com Sequence, o Sql Server e o MySQL trabalham com Identity.
Identity
Esse é o tipo de geração automática mais simples que existe, basta anotar o atributo id, com @GeneratedValue
(strategy = GenerationType.IDENTITY). Utilizado pelo SQL Server e o MySQL. Exemplo:
@Entity public class Celular { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private int numero; }
Sequence
O tipo de geração de id por Sequence, é o utilizado pelo Oracle e pelo PostgreSQL, utilizando a anotação@GeneratedValue
(strategy = GenerationType.SEQUENCE, generator = "NOME_DA_SEQUENCE"). Exemplo:
@Entity @SequenceGenerator(name ="QUALQUER NOME", sequenceName = "NOME_DA_SEQUENCE_NO_BANCO", allocationSize = 1) public class Celular { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "QUALQUER NOME") private int id; private int numero;
Primeiramente defina o gerador de sequencia nas anotações da classe, configure o nome da Sequence no banco e mais algumas poucas propriedade se quiser e dê um apelido. Em seguida na propriedade com a anotação @Id, adicione outra anotação, a @GeneratedValue, configurando a strategy(do grego “estrategí”) para Sequence e na propriedade generator, utilize o apelido utilizado na anotação @SequenceGenerator no início da entidade.
@ConstructResult – Mapeando SQL complexos para um POJO
Esse aqui foi um inferno descobrir como fazer. Eu sempre fiz da maneira errada utilizando a anotação @Entity em um POJO e deixando a opção de validação do hibernate desligada, senão dava erro, e demorou para descobrir, só aprendi quando troquei de emprego. Então, saí em uma caçada pela forma correta de fazer isso e enfim…
Primeiro você cria um pojo simplão e adiciona um construtor com todos os campos do pojo e que serão retornados na query.
public class ResultTesteDTO implements Serializable{ private static final long serialVersionUID = 6873051541292059290L; public ResultTesteDTO(Integer idProduto, Integer valorTotal) { super(); this.idProduto = idProduto; this.valorTotal = valorTotal; } public Integer idProduto; public Integer valorTotal; public Integer getIdProduto() { return idProduto; } public void setIdProduto(Integer idProduto) { this.idProduto = idProduto; } public Integer getValorTotal() { return valorTotal; } public void setValorTotal(Integer valorTotal) { this.valorTotal = valorTotal; } }
@SqlResultSetMapping(name = "QueryComplexa", classes = { @ConstructorResult(targetClass = ResultTesteDTO.class, columns = { @ColumnResult(name = "id_produto", type=Integer.class), @ColumnResult(name = "TOTAL", type=Integer.class) }) })
public List listaTeste(final Long idProduto) { final Query query = em.createNativeQuery("select p.id_produto, count(*) TOTAL from produto p\n"+ "group by p.id_produto", "QueryComplexa"); final List<ResultTesteDTO> lista = query.getResultList(); return lista; }
Aaaaaaaaaaaaaaaaaaaaaaaeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!!!!!!!!!!!!!!!!!!
Ah, meus sinceros agradecimentos: http://stackoverflow.com/questions/29636004/where-to-place-sqlresultsetmapping-in-case-of-constructorresult.
Agora que conheço a forma teoricamente correta de se fazer isso, percebo a outra forma era mais elegante e simples de implementar, bem mais elegante e simples por sinal. Segue abaixo a forma como fazia anteriormente:
@Entity @SqlResultSetMapping(name = "ResultTesteDTO", entities = @EntityResult(entityClass = ResultTesteDTO.class)) public class ResultTesteDTO implements Serializable{ private static final long serialVersionUID = 6873051541292059290L; public static final String sql = "select p.id_produto, count(*) total from produto p group by p.id_produto";&amp;lt;/pre&amp;gt;&amp;lt;pre&amp;gt;@Id @Column(name = "id_produto") public Integer idProduto; @Column(name = "total") public Integer valorTotal; }
public List listaTeste(final Long idProduto) { final Query query = em.createNativeQuery("select p.id_produto, count(*) TOTAL from produto p group by p.id_produto", ResultTesteDTO.class); final List<ResultTesteDTO> lista = query.getResultList(); return lista; }
- Anotava o proprio DTO com @Entity;
- Anotava com @SqlResultSetMapping, configurando a própria classe e dando um nome quaquer;
- Anotava as propriedades com @Column, utilizando os campos do SQL, que já mantinha na própria classe;
- Usaria nas consultas como se fosse uma entidade normalmente;
Guia de Referência
@Table(name=”nome da tabela”) – Uma tabela e seu nome
@Id – Chave primária
@SequenceGenerator(name =”QUALQUER NOME”, sequenceName = “NOME_DA_SEQUENCE_NO_BANCO”, allocationSize = 1) – Define o gerador de sequência e seu apelido
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “QUALQUER NOME”) – Informa qual o gerador de sequencia será utilizado
@OneToOne(mappedBy=”nome da propriedade”) – Relacionamente UmParaUm
mappedBy=”nome da propriedade” – Utilizado quando o mapeamento não é o lado dominante.
@OneToMany – Relacionamento UmParaMuitos
@ManyToOne – Relacionamento MuitosParaUm. Não pode utilizar mappedBy.
@JoinColumn – indica que a chave estrangeira ficará dentro da própria tabela (Pessoa), fazendo com que a entidade Pessoa seja a dona do relacionamento. Utilizado no @OneToOne ou no @OneToMany
@SqlResultSetMapping(name = “Nome da Query”, classes = { @ConstructorResult(targetClass = AlgumPOJO.class, columns = { @ColumnResult(name = “nome da coluna”, type=Integer.class) }) }) – Mapeando um POJO qualquer para ser utilizado para mapear uma query complexa.
Bibliografia
http://uaihebert.com/jpa-mini-livro-primeiros-passos-e-conceitos-detalhados/19/
hauahauhauahua… seu post além de estar super informativo, está muito engraçado! ahahahaha
Pastei tanto com esse trem lá na Certisign… mas até que era divertido…
Parabéns, Marcelo! Certeza que isso vai ajudar muitas pessoas!
beijos
CurtirCurtir
Lendo te dá saudades ou depressão? Kkkk
Acho que já sei a resposta. Agora você deve se preocupar com fisiológica, nutrição, …..
Obrigado pelo apoio, preciso escrever senão esqueço tudo.
Ah, peguei meu diploma essa semana lá na USJT! Deu até saudade, mas passou bem rápido kkkkk.
CurtirCurtir