Baixe o app para aproveitar ainda mais
Prévia do material em texto
CENTRO UNIVERSITÁRIO DE PATOS DE MINAS DISCIPLINA: DESENVOLVIMENTO WEB II EDUARDO HENRIQUE SILVA MAPEAMENTO OBJETO RELACIONAL COM JPA SUMÁRIO 1 INTRODUÇÃO ......................................................................................... 1 1.1 O QUE É PERSISTÊNCIA ............................................................................................ 1 1.2 PERSISTÊNCIA NO PARADIGMA ORIENTADO A OBJETO ................................ 1 2 MAPEAMENTO OBJETO RELACIONAL (ORM) ............................ 1 2.1 POR QUE USAR O ORM? ............................................................................................ 2 2.2 CAMADA DE PERSISTÊNCIA ................................................................................... 2 2.3 JAVA PERSISTENCE API (JPA) ................................................................................. 2 3 MAPEANDO ENTIDADES ..................................................................... 3 3.1 POJO ............................................................................................................................... 3 3.2 CRIANDO DE ENTIDADES ........................................................................................ 4 3.2.1 Anotações @Entity e @Table ......................................................................................... 5 3.2.2 Anotações @Id e @GeneratedValue .............................................................................. 6 3.2.3 Anotações @Column e @Basic ...................................................................................... 7 3.2.4 Anotação @Temporal ..................................................................................................... 9 3.2.5 Anotação @Transient ................................................................................................... 10 3.2.6 Mapeando a tabela Automóvel ..................................................................................... 11 4 MAPEANDO ASSOCIAÇÕES ............................................................. 12 4.1 RELACIONAMENTO UM PARA UM @ONETOONE ............................................. 12 4.1.1 Anotação @OneToOne ................................................................................................. 13 4.1.2 Anotações @PrimaryKeyJoinColumn e @JoinColumn ............................................... 14 4.1.3 Mapeando a classe pessoa ............................................................................................ 15 4.1.4 Cascade ......................................................................................................................... 16 4.2 MAPEANDO COM O USO DA HERANÇA .............................................................. 17 4.3 RELACIONAMENTO UM PARA MUITOS @ONETOMANY E @MANYTOONE . 19 4.3.1 Anotação @ManyToOne .............................................................................................. 20 4.3.2 Anotação @ManyToOne .............................................................................................. 20 4.4 RELACIONAMENTO MUITOS PARA MUITOS @MANYTOMANY ...................... 21 5 OUTRAS ANOTAÇÕES ........................................................................ 24 5.1 CHAVE PRIMÁRIA COMPOSTA ............................................................................. 24 5.2 ANOTAÇÃO @NAMEDQUERY ................................................................................. 25 6 UNIDADE DE PERSISTÊNCIA ........................................................... 26 7 GERENCIANDO OBJETOS PERSISTENTES .................................. 27 7.1 ENTITY MANAGER ...................................................................................................... 27 7.1.1 Entity Manager gerenciado pelo contêiner ................................................................... 28 7.1.2 Entity Manager gerenciado pela aplicação ................................................................... 29 7.1.3 Contexto de persistência ............................................................................................... 29 8 JAVA PERSISTENCE QUERY LANGUAGE ....................................... 30 8.1 CRIANDO CONSULTAS ............................................................................................ 31 8.2 ESTRUTURA BÁSICA ............................................................................................... 32 8.2.1 Where ............................................................................................................................ 33 8.2.2 Outras consultas ............................................................................................................ 33 8.3 MÉTODOS PARA CRIAR CONSULTAS .................................................................. 33 8.3.1 Named Queries ............................................................................................................. 34 8.3.2 Dynamic Queries .......................................................................................................... 35 8.3.3 Invocando uma consulta ............................................................................................... 35 8.3.4 Passagem de parâmetros ............................................................................................... 36 REFERÊNCIAS ................................................................................................ 36 1 1 INTRODUÇÃO 1.1 O QUE É PERSISTÊNCIA Persistência é um dos conceitos fundamentais no desenvolvimento de aplicações. Se um software não preservar os dados quando ele for desligado, o software será de pouco uso prático. Quando falamos de persistência, normalmente estamos falando sobre como guardar dados em um banco de dados. 1.2 PERSISTÊNCIA NO PARADIGMA ORIENTADO A OBJETO Em uma aplicação orientada a objetos, a persistência permite guardar o estado (valores dos atributos) de um objeto em disco. Em uma aplicação Java podemos ter objetos persistentes e objetos transientes, um objeto transiente possui a vida limitada determinada pelo processo que o instanciou. Na persistência, geralmente utilizamos um banco de dados relacional, que possui interfaces de programação baseadas em SQL. Banco de dados relacional é orientação a objetos são representações totalmente diferentes. Em um banco de dados relacional temos tabelas, registros, e colunas, na OO temos classes, objetos, atributos e métodos. O desafio é fazer os nossos objetos serem persistidos em um banco de dados relacional. 2 MAPEAMENTO OBJETO RELACIONAL (ORM) O mapeamento objeto relacional (ORM) permite que os nossos objetos sejam persistidos em um banco de dados relacional. Podemos mapear entidades (classes) para tabelas e atributos para colunas utilizando metadados que descrevem o mapeamento entre eles. O ORM trabalha com a transformação dos dados de uma representação para outra, permitindo a persistência automatizada e transparente dos objetos em uma aplicação Java para as tabelas de um banco de dados relacional. 2 2.1 POR QUE USAR O ORM? Produtividade: O ORM elimina muitas tarefas rotineiras do trabalho e deixa você se concentrar no problema do negócio. Por exemplo: Não é necessário escrever comandos de inserção e alteração em SQL para cada tabela do banco de dados; Manutenibilidade: O ORM reduz substancialmente as linhas de código, e permite o isolamento das representações orientado a objetos e banco de dados relacional; Desempenho: O desempenho de um software com a persistência implementada a mão (sem utilização do ORM), pode ser mais rápida, quando uma persistência ORM. Em contraparte, o ORM permite otimizaçõese ainda melhora a produtividade dos desenvolvedores; Independência: O ORM abstrai a sua aplicação da interação direta com o banco de dados SQL, permitindo a portabilidade, ou seja, nossa aplicação poderá mudar de fornecedor de banco de dados sem precisar ser reestruturada. 2.2 CAMADA DE PERSISTÊNCIA A camada de persistência é o grupo de classes e componentes responsáveis por guardar os dados e recupera-los em um ou vários repositórios de dados. Essa camada necessariamente inclui o modelo das entidades de domínio de negócio. 2.3 JAVA PERSISTENCE API (JPA) Java Persistence API é uma especificação ORM do JEE que trata exclusivamente da persistência, entidades, metadados, mapeamento objeto relacional, interfaces para gerenciar a persistência, e a linguagem de consulta. Através do JPA podemos mapear através de anotações as entidades para tabelas e atributos para colunas, além persistir e recuperar objetos. 3 3 MAPEANDO ENTIDADES 3.1 POJO Plain Old Java Objects (POJOs – o bom e velho objeto puro Java) é uma abordagem “de volta às raízes” que essencialmente ressuscita o JavaBeans, um modelo de componente para desenvolvimento de UI, e a reaplica-los na camada de negócios. A maioria dos desenvolvedores usa agora o termo POJO e JavaBeans quase como sinônimos. Um POJO declara métodos de negócios, que definem o comportamento, e propriedades, que representam o estado. Algumas propriedades representam associações para outros POJOs. No modelo de persistência do JPA, uma entidade é um POJO. O código abaixo mostra uma classe POJO, implementando a entidade Cor. public class Cor implements Serializable { ← Implementação do Serializable private static final long serialVersionUID = 1L; private Short idCor; ← Atributos encapsulados private String descricao; public Cor(){← Construtor da classe sem argumentos } public Short getIdCor() {← Métodos de acesso aos atributos return idCor; } public void setIdCor(Short idCor) { this.idCor = idCor; } public String getDescricao() { return descricao; } public void setDescricao(String descricao) { this.descricao = descricao; } } Então um POJO deve ter apenas atributos encapsulados e métodos de acesso, bem como, um construtor sem argumentos. A interface Serializable é opcional, embora ele seja obrigatório quando for necessário transmitir o objeto através de uma interface remota (RMI) ou armazena-lo em uma 4 sessão do navegador de internet. Através dela podemos transformar um objeto em uma cadeia de caracteres e vice-versa. 3.2 CRIANDO DE ENTIDADES Agora iremos criar as nossas entidades baseado no diagrama de entidade e relacionamento apresentado na apostila “Desenvolvimento Java EE”. Na apostila “Desenvolvimento Java EE” foi apresentado como criar o projeto no NetBeans, dando sequência iremos criar nossas entidades no projeto “br.com.aula.javaweb-ejb”, pois, ele contém todas as regras de negócios do software. Clique com o botão direito em cima do projeto selecione o menu “Novo/Pacote Java”. Crie um pacote com o nome “br.com.aula.javaweb.entity”. Nossas classes de entidades serão criadas nesse pacote. Inicialmente, será apresentado como mapear as classes, posteriormente iremos realizar o mapeamento das associações. Iremos realizar o mapeamento objeto relacional na tabela “Marca”. No mapeamento objeto relacional, uma tabela será uma classe, e as colunas serão atributos da classe. E cada registro na tabela será um objeto. O código abaixo é referente ao public class Marca implements Serializable { private static final long serialVersionUID = 1L; private Short idMarca; private String descricao; //Métodos get/set } Veja que cada coluna no banco de dados possui um tipo, e na classe também devemos informar o tipo do atributo, porém, os tipos em um banco de dados relacional nem sempre são iguais os tipos na orientação a objetos, por exemplo, “Varchar” e “String”, não há o tipo “Varchar” em Java, porém ambos são tipos inerentes. Na orientação a objetos 5 geralmente possui tipos inerentes ao banco de dados relacional. A tabela abaixo apresenta os tipos em Java referentes os tipos SQL. Tipo inerente ao padrão SQL Tipo Java INTERGER int ou java.lang.Integer BIGINT long ou java.lang.Long SMALLINT short ou java.lang.Short FLOAT float ou java.lang.Float DOUBLE double ou java.lang.Double NUMERIC java.math.BigDecimal CHAR(1) java.lang.String VARCHAR java.lang.String TINYINT byte ou java.lang.Byte BIT boolean ou java.lang.Boolean DATE java.util.Date TIME java.util.Date VARBINARY byte[] BLOB java.sql.Blob Em Java podemos definir os tipos dos atributos usando tipos primitivos como “int” ou tipo Wrapper como “java.lang.Integer”. Os Wrappers são representações dos tipos primitivos em forma de objetos. Os Wrappers possuem métodos de conversão de dados, e podem receber o valor nulo, enquanto, um tipo primitivo não pode recever valor nulo. 3.2.1 Anotações @Entity e @Table Para mapear uma classe com o JPA utilizaremos as anotações (annotations) representadas pelo sinal “@”, elas estão presentes no pacote “javax.persistence”. Vamos começar pela classe “Marca”. @Entity @Table(name = "marca") public class Marca implements Serializable { private static final long serialVersionUID = 1L; } A anotação “@Entity” permite ao provedor de persistência reconhece a classe como uma classe persistente e não como um simples POJO. A anotação “@Table” é opcional, ela diz para qual tabela do banco de dados a classe está mapeada, através do atributo “name”. Se essa anotação não for especificada então, 6 o JPA assume que a tabela possui o mesmo nome da classe. Se a tabela e a classe tiverem nomes diferentes então é necessário utilizar essa anotação. O banco de dados padrão é definido no arquivo de configuração do JPA. Podemos especificar entidades para tabelas de banco de dados diferentes do definido no arquivo de configuração “@Table(name = "marca",schema = "javaweb")”, utilizando o atributo “schema” para especificar qual o banco de dados da tabela. 3.2.2 Anotações @Id e @GeneratedValue Em um banco de dados relacional, a chave primária identifica cada registro na tabela. A chave primária deve ser única e não permite valores nulos. A tabela “Marca” a chave primária é representada pela coluna “idMarca” auto incremental, vamos então mapeá- la. @Entity @Table(name = "marca") public class Marca implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idMarca",nullable = false) private Short idMarca; //Métodos get/set } A anotação “@Id” é utilizado para dizer que o atributo é uma chave primária, sendo um identificar exclusivo para o conjunto de dados. A anotação “@GeneratedValue”, é utilizada para denotar que o valor do atributo “idMarca” o seu valor será gerado automaticamente pela aplicação ou pelo provedor de persistência. Essa anotação pode possuir quatro estratégias: IDENTITY especifica que o provedor de persistência deve gerar o valor da do atributo usando a coluna de identidade do banco de dados “@GeneratedValue(strategy=GenerationType.IDENTITY)”; 7 TABLE especifica que o provedor de persistência deve gerar o valor do atributo usando uma tabela do banco de dados para garantir a exclusividade “@GeneratedValue(strategy=GenerationType.TABLE)”; SEQUENCEespecifica que o provedor de persistência deve gerar o valor do atributo usando uma coluna de sequência de dados “@GeneratedValue(strategy=GenerationType. SEQUENCE)”; AUTO especifica que o provedor de persistência deve escolher a estratégia adequada para gerar o valor do atributo “@GeneratedValue(strategy=GenerationType.AUTO)” ou “@GeneratedValue”; 3.2.3 Anotações @Column e @Basic A anotação “@Column” é opcional, ela permite mapear a coluna da tabela com o atributo. Se a coluna da tabela tiver o mesmo nome do atributo, essa anotação é opcional. Nessa anotação temos os seguintes atributos: name (String): indica o nome da coluna da tabela que o atributo está mapeando; unique (boolean): indica se a coluna da tabela é único (padrão “false”); nullable (boolean): indica se a coluna poderá receber valores nulos (padrão “true”); lenght (int): indica a capacidade máxima de caracteres (usado apenas para atributos que armazenam cadeias de caracteres como String) (padrão “255”); insertable (boolean): indica se na inserção do objeto, o atributo também deve ser inserido (padrão “true”); updatable (boolean): indica se na alteração do objeto, o atributo também deve ser alterado (padrão “true”);. Essa anotação não é obrigatória, se seus atributos estão bem mapeados, você pode realizar uma engenharia reversa e gerar banco de dados de acordo com os mapeamentos, caso necessário. 8 Agora iremos mapear as colunas não chaves, na tabela “Marca”, temos apenas a coluna “descricao”. @Entity @Table(name = "marca") public class Marca implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idMarca",nullable = false) private Short idMarca; @Column(name = "descricao",nullable = false,length = 50) private String descricao; //Métodos get/set } Para mapear a coluna “descricao” utilizou apenas a anotação “@Column”, que não é obrigatório. Foi utilizado o atributo “length”, que diz ao provedor de persistência que o atributo pode ter até 50 caracteres. A anotação “@Basic” é opcional, utilizada para mapear uma coluna do tipo numérico ou texto. Ela possui dois atributos: fetch (FetchType): diz para o provedor de persistência em tempo de execução se o dado deve ser carregado preguiçosamente (“FetchType.LAZY” a aplicação diz se ela quer que o dado seja carregado) ou ansiosamente (“FetchType.EAGER” toda vez que a entidade é buscada o dado também é carregado) (padrão “EAGER”); opcional (boolean): diz para o provedor de persistência se o valor pode ser nulo (mesma função do “nullable” da anotação “@Column”) (padrão “true”);. Veja um exemplo de uma anotação “@Basic”. @Basic(fetch = FetchType.LAZY,optional = false) @Column(name = "descricao",nullable = false,length = 50) private String descricao; Essa anotação é usada geralmente quando você não quer que o atributo seja carregado automaticamente ao realizar uma busca. Nesse projeto não utilizaremos a anotação “@Basic”. 9 Pronto, a entidade está mapeada. Veja o código final. @Entity @Table(name = "marca") public class Marca implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idMarca",nullable = false) private Short idMarca; @Column(name = "descricao",nullable = false,length = 50) private String descricao; //Métodos get/set } 3.2.4 Anotação @Temporal Em Java, podemos usar o “java.util.Date” ou “java.Util.Calendar” para armazenar datas e suas várias representações, como, data, hora, minutos ou milissegundos. Para especificar isso no mapeamento objeto relacional podemos usar a anotação “@Temporal”. Essa anotação possui três possibilidades de valor: DATE: utilizado para representar apenas datas (dia, mês e ano); TIME: utilizando para representar apenas tempo (horas, minutos, segundos e milissegundos); TIMESTAMP: utilizado para representar data e horas (dias, mês, ano, horas, segundos, e milissegundos). A tabela “Pessoa” possui um campo do tipo “Date”, vamos realizar o mapeamento dessa tabela. 10 @Entity @Table(name = "pessoa") public class Pessoa implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idPessoa",nullable = false) private Integer idPessoa; @Column(name = "nome",nullable = false,length = 100) private String nome; @Column(name = "cpf",nullable = false,length = 14) private String cpf; @Column(name = "dataNascimento",nullable = false) @Temporal(TemporalType.DATE) private Date dataNascimento; //Métodos get/set } Como a data de nascimento de uma pessoa não possui, horas e nem minutos, essa coluna foi mapeada com o tipo “Date”. Toda coluna que representar uma data ou tempo deve ter a anotação “@Temporal”. 3.2.5 Anotação @Transient Com o JPA, a classe que é anotada com o “@Entity”, todos os atributos são automaticamente mapeados para a tabela. Se não for necessário mapear um atributo, você pode usar o “@Transient”. Por exemplo, anteriormente mapeamos a tabela “Pessoa”, essa tabela possui o atributo data de nascimento. Poderíamos adicionar ainda o atributo idade, que seria calculado a partir da data de nascimento, porém esse atributo não seria persistido no banco de dados, ele seria um atributo transiente. Veja o exemplo. @Entity @Table(name = "pessoa") public class Pessoa implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idPessoa",nullable = false) private Integer idPessoa; 11 @Column(name = "nome",nullable = false,length = 100) private String nome; @Column(name = "cpf",nullable = false,length = 14) private String cpf; @Column(name = "dataNascimento",nullable = false) @Temporal(TemporalType.DATE) private Date dataNascimento; @Transient private Integer idade; //Métodos get/set //Método para calcular a idade; } 3.2.6 Mapeando a tabela Automóvel Já estudamos as anotações básicas para mapear uma entidade, como mais um exemplo, segue o código do mapeamento da tabela Automóvel. @Entity @Table(name = "automovel") public class Automovel implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idAutomovel",nullable = false) private Integer idAutomovel; @Column(name = "ano",nullable = false) private Integer ano; @Column(name = "valor",nullable = true) private Double valor; @Column(name = "quantidadePortas",nullable = false) private Short quantidadePortas; //Métodos get/set } Observe-se que na coluna “valor”, o atributo “nullable” do mapeamento “@Column” está como “true”. Pois nesse campo, de acordo com o banco de dados, pode receber valores nulos. Bom, agora você é capaz de mapear todas as tabelas no banco de dados. 12 4 MAPEANDO ASSOCIAÇÕES Em um projeto orientado a objetos está repleto de classes e associações entre as classes. Essas associações são estruturas que ligam objetos de um tipo para objetos de outro tipo, permitindo um objeto delegarfuncionalidades a outros objetos. Vários tipos de associações podem existir entre as classes. Em um banco de dados relacional podemos ter diversas relações entre tabelas. No banco de dados relacional, um relacionamento é indicado pela chave estrangeira, na orientação a objetos uma associação é indicada por uma referência de uma classe. Com as anotações do JPA poderemos mapear essas associações de acordo com o modelo relacional. 4.1 RELACIONAMENTO UM PARA UM @ONETOONE No diagrama de entidade e relacionamento possuímos dois relacionamentos um para um. Um relacionamento um para um de “Pessoa” para “Funcionário” e outro relacionamento de um para um de “Pessoa” para “Usuário”. Na programação orientada a objetos, podemos adotar que a classe “Funcionário” é uma subclasse de “Pessoa”, pois, uma pessoa é um funcionário. Então no relacionamento de “Pessoa” para “Funcionário” adotaremos outra estratégia de mapeamento, utilizando o conceito de herança. Primeiramente, mapearemos o relacionamento de um para um com “Pessoa” e “Usuário”. @Entity @Table(name = "usuario") public class Usuario implements Serializable { 13 private static final long serialVersionUID = 1L; @Id @Column(name = "idPessoa",nullable = false,updatable = false,insertable = false) private Integer idPessoa; @Column(name = "login",nullable = false,length = 45) private String login; @Column(name = "senha",nullable = false,length = 150) private String senha; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "idPessoa",nullable=false) private Pessoa pessoa; //Métodos get/set } Quando dizemos que um usuário pode ser de apenas uma pessoa, estamos dizendo que um objeto usuário pode ter apenas uma referência do objeto pessoa. A referência “private Pessoa pessoa;”, indica que o objeto usuário é de apenas uma pessoa. 4.1.1 Anotação @OneToOne A anotação “@OneToOne”, indica para o provedor de persistência que um relacionamento entre as entidades é de um para um. Nessa associação temos um atributo denominado “fetch”, com a mesma característica do “fetch” presente na anotação “@Basic”. O valor padrão é “EAGER” FetchType.LAZY diz para o provedor de persistência que a referência deve ser carregada preguiçosamente, ou seja, a referência é buscada apenas se a aplicação solicitar; FetchType.EAGER diz para o provedor de persistência que a referência deve ser carregada ansiosamente, ou seja, toda vez que a entidade for buscada a referência também deve ser buscada. Geralmente, mapeamos as associações com o “LAZY”, pois, imagine um busca por um objeto que possui várias associações, e nessa busca todas as associações são carregadas, sendo que nem sempre utilizaremos todas as associações. Isso pode gerar um 14 problema de desempenho em determinadas funções. Com o “LAZY”, a aplicação que vai definir quando e quais associações serão carregadas. 4.1.2 Anotações @PrimaryKeyJoinColumn e @JoinColumn Também utilizamos a anotação “@PrimaryKeyJoinColumn”, para mapear a chave estrangeira presente na tabela que estamos mapeando. Utilizamos dois atributos: name: utilizado para informar o nome da coluna referente a chave estrangeira que define a associação da tabela; referencedColumnName: utilizado para informar o nome da coluna chave primária da tabela relacionada, que virá para a tabela mapeada como chave estrangeira. Se a chave primária da tabela relacionada tiver o mesmo nome da chave estrangeira, essa anotação não é obrigatória. Quando a chave estrangeira também for uma chave primária utilizamos o “@PrimaryKeyJoinColumn”, porém quando a chave for apenas estrangeira utilizamos o “@JoinColumn”. O “@JoinColumn” possui alguns atributos adicionais: unique (boolean): indica se a chave estrangeira da tabela é único (padrão “false”); nullable (boolean): indica se a chave estrangeira poderá receber valores nulos (padrão “true”); insertable (boolean): indica se na inserção do objeto, a chave estrangeira também deve ser inserido (padrão “true”); updatable (boolean): indica se na alteração do objeto, a chave estrangeira também deve ser alterado (padrão “true”);. Quando uma tabela possui mais de uma chave estrangeira vindo de uma outra tabelas, utilizamos as anotações “@PrimaryKeyJoinColumns(value={})” e “@JoinColumns(value={})”. Onde podemos passar através do atributo “value” uma coleção de “@JoinColumn” ou “@PrimaryKeyJoinColumn”. Veja um exemplo: 15 @JoinColumns(value = { @JoinColumn(name = "idTeste1",nullable = false), @JoinColumn(name = "idTeste2",nullable = false)}) private Combustivel combustivel; 4.1.3 Mapeando a classe pessoa No exemplo anterior mapeamos o relacionamento de usuário para funcionário. Iremos realizar o mapeamento bidirecional, então será necessário realizar o mapeamento de funcionário para o usuário. @Entity @Table(name = "pessoa") public class Pessoa implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idPessoa",nullable = false) private Integer idPessoa; @Column(name = "nome",nullable = false,length = 100) private String nome; @Column(name = "cpf",nullable = false,length = 14) private String cpf; @Column(name = "dataNascimento",nullable = false) @Temporal(TemporalType.DATE) private Date dataNascimento; @OneToOne(fetch = FetchType.LAZY,mappedBy = "pessoa",cascade = CascadeType.ALL) private Usuario usuario; //Métodos get/set } Na tabela “Pessoa” não há chave estrangeria referente a tabela “Usuário” então não precisamos do “@JoinColumn”. Porém, precisamos do atributo “mappedBy”. O “mappedBy” identifica o atributo que possui o mapeamento da associação, ele é necessário para relacionamentos bidirecionais. Veja: @Entity @Table(name = "pessoa") public class Pessoa{ 16 //Outos atributos @OneToOne(fetch = FetchType.LAZY, mappedBy = "pessoa", cascade = CascadeType.ALL) private Usuario usuario; //Métodos get/set } @Entity @Table(name = "usuario") public class Usuario { //Outros atributos @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "idPessoa",) private Pessoa pessoa; //Métodos get/set } O valor do “mappedBy” deve ser o nome da referência que possui o mapeamento. 4.1.4 Cascade Na classe “Pessoa” utilizou um atributo denominado “cascade” no mapeamento do relacionamento com a classe “Usuário”. Esse atributo permite realizar ações em cascata, ou seja, as operações efetuadas nos objetos serão propagadas para as os atributos que estão mapeados com o “cascade”. Ele pode ser utilizado em qualquer mapeamento de associações. O JPA fornece quatro valores possíveis para o “cascade”. ALL: equivale as operações de MERGE, PERSIST, REFRESH e REMOVE; MERGE: se o estado do objeto for transferido para o banco de dados, então a associação também será transferida; PERSIST: se o objeto for persistido, então a associação também será persistida; REFRESH: se o objeto for atualizado a partir do banco de dados, então a associação também será atualizada; REMOVE: se objeto for removido, então a associação também será removida. 17 No exemplo da classe “Pessoa” utilizamos o “Cascade.ALL” para a associação “usuário”. Isso diz, que quando eu salvar, excluir, alterar um objeto do tipo pessoa, também será salvado, excluído ou alteradoo objeto usuário, sem a necessidade de algum código adicional. 4.2 MAPEANDO COM O USO DA HERANÇA Herança é um conceito completamente desconhecido e não implementado em banco de dados relacional. O JPA permite mapear tabelas do banco de dados relacional para uma associação de herança da orientação a objeto. No projeto, temos as classes “Pessoa” e “Funcionário” que podem ser respectivamente, superclasse e subclasse, e no banco de dados formam um relacionamento um para um. Primeiramente vamos mapear a superclasse “Pessoa”. @Entity @Table(name = "pessoa") @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name = "tipo",discriminatorType = DiscriminatorType.CHAR) public class Pessoa implements Serializable { //Atributos e mapeamentos //Métodos get/set } A anotação “@DiscriminatorColumn” é utilizada para identificar a coluna da entidade “Pessoa” que irá armazenar qual o tipo de entidade que o registro está associado. 18 Exemplo: Se um registro na tabela “Pessoa” possui o valor “F” na coluna “tipo”, então esse registro está associado a um registro na tabela “Funcionário”. Na superclasse a única mudança é o mapeamento “@Inheritance” que define qual estratégia adotada no banco de dados relacional. Considere o diagrama de classe abaixo para entender as três estratégias de mapeamento do JPA: JOINED: cada entidade na hierarquia é mapeada com seus atributos; SINGLE_TABLE: todos os atributos das classes na hierarquia serão colocados e uma única tabela; TABLE_PER_CLASS: cada entidade concreta na hierarquia possui sua própria tabela. Na maioria das vezes usamos a estratégia “JOINED”, devido ao uso das formas normais ao desenvolver o modelo de entidade e relacionamento. O próximo passo é mapear a subclasse “Funcionário”. 19 @Entity @Table(name = "funcionario") @PrimaryKeyJoinColumn(name ="idPessoa") @DiscriminatorValue("F") public class Funcionario extends Pessoa{ @Column(name = "salario",nullable = false) @NotNull(message = "Informe o salário") private Double salario; //Métodos get/set } Observe-se que não possuímos um atributo que mapeia a chave estrangeira, pois iremos reusar todos os atributos na classe “Pessoa”. Nesse mapeamento não se esqueça de usar a declaração “extends”. A anotação “@DiscriminatorValue” irá dizer qual valor será inserido no campo “@Discriminator” na entidade pai. Na subclasse, devemos apenas mapear qual a coluna chave primária. Não necessário criar um atributo para essa coluna. Para mapear a chave primaria usamos a anotação “@PrimaryKeyJoinColumn” já vista anteriormente em um relacionamento um para um. Essa anotação deve ser realizada na classe. No atributo “name” será passado o nome da chave primária e estrangeira da tabela “Funcionário” e na “referecedColumnName” o nome da chave primária que veio da tabela "Pessoa". 4.3 RELACIONAMENTO UM PARA MUITOS @ONETOMANY E @MANYTOONE No diagrama de entidade e relacionamento do projeto, possui vários relacionamentos de um para muitos entre as tabelas. Como exemplo, mapearemos o relacionamento de um para muitos entre “Marca” e “Modelo”. 20 4.3.1 Anotação @ManyToOne Nesse relacionamento podemos dizer que uma marca possui zero ou vários modelos, e um modelo é de apenas uma marca. Primeiramente, será mapeada a tabela que possui a chave estrangeira referente ao relacionamento de um para muitos, nesse caso a tabela “Modelo”. @Entity @Table(name = "modelo") public class Modelo implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idModelo",nullable = false) private Short idModelo; @Column(name = "descricao",nullable = false,length = 50) private String descricao; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "idMarca",nullable = false) private Marca marca; //Métodos get/set } Conforme apresentado anteriormente, um Modelo é de apenas uma Marca, então na classe “Modelo” terá uma referência da classe “Marca”. A anotação “@ManyToOne” indica um relacionamento onde um modelo poder ter apenas uma marca (e uma marca pode ter vários modelos). Essa anotação permite os atributos “fetch” e “cascade” já apresentados anteriormente. A anotação “@JoinColumn” indica o mapeamento da chave estrangeira, essa anotação também já foi apresentada anteriormente. 4.3.2 Anotação @ManyToOne Agora, será realizado o mapeamento bidirecional, nesse caso a tabela “Marca”. Onde dissemos que uma marca pode ter zero ou vários modelos. @Entity @Table(name = "marca",schema = "javaweb") public class Marca implements Serializable { private static final long serialVersionUID = 1L; 21 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idMarca",nullable = false) private Short idMarca; @Basic(fetch = FetchType.EAGER,optional = false) @Column(name = "descricao",nullable = false,length = 50) private String descricao; @OneToMany(fetch = FetchType.LAZY,mappedBy = "marca") private List<Modelo> modelos; //Métodos get/set } Como dito, uma marca pode ter vários modelos. Um objeto “Marca” deve possuir uma coleção de objetos do tipo “Modelo”, para declarar uma coleção podemos utilizar as interfaces “List” ou “Set”. Nessa associação utilizou a anotação “@OneToMany” indicando que é uma relacionamento um para muitos. Essa anotação permite os atributos “fetch”, “cascade” e o “mappedBy” para indicar qual referência está mapeado o relacionamento. Pronto, agora você pode realizar os mapeamentos de um para muitos de “Automóvel” para “Cor”, “Automóvel” para “Combustível”, “Automóvel” para “Modelo” e “Automóvel” para “AutomovelFoto”. 4.4 RELACIONAMENTO MUITOS PARA MUITOS @MANYTOMANY No diagrama de entidade e relacionamento possuímos um relacionamento de muitos para muitos entre as tabelas “Automóvel” e “Opcional” criando a tabela do meio denominada “AutomovelOpcional”. 22 No mapeamento objeto relacional não é necessário a criação da classe que mapeia a tabela do meio. Teremos uma associação entre as classes de muitos para muitos. Um objeto “Automóvel” possui uma coleção de objetos do tipo “Opcional” e vice versa. No mapeamento de muitos para muitos, podemos escolher uma classe para mapear a tabela do meio. Nesse exemplo, vamos mapear a tabela do meio na classe “Automóvel”. @Entity @Table(name = "automovel") public class Automovel implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idAutomovel",nullable = false) private Integer idAutomovel; @Column(name = "ano",nullable = false) private Integer ano; @Column(name = "valor",nullable = true) private Double valor; @Column(name = "quantidadePortas",nullable = false) private Short quantidadePortas; @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "AutomovelOpcional", joinColumns = @JoinColumn(name = "idAutomovel"), inverseJoinColumns = @JoinColumn(name = "idOpcional")) private List<Opcional> opcionais; //Métodos get/set } A anotação “@ManyToMany” indica um relacionamento de muitos para muitos, ela pode conter os atributos “fetch”, “cascade” e “mappedBy” (usado para criar o mapeamento bidirecional) apresentados anteriormente.A anotação “@JoinTable” é utilizada para mapear uma tabela que se relaciona com a tabela que está sendo mapeada. O atributo “name” identifica o nome da tabela, nesse 23 exemplo, a tabela do meio “AutomovelOpcional” será mapeada na associação, não sendo necessário uma classe. O atributo “joinColumns” recebe uma coleção de “@JoinColumn” referentes as chaves estrangeiras e primárias da tabela do meio que também são chaves primárias na classe que está mapeada a anotação “@JoinTable”. O atributo “inverseJoinColumns” recebe uma coleção de “@JoinColumn” referentes as chaves estrangerias e primárias da tabela do meio que também são chaves primárias da classe referenciada (classe inversa). Para realizar o mapeamento bidirecional, iremos mapear uma coleção de automóveis na classe “Opcional”, não será necessário o uso do “@JoinTable”. @Entity @Table(name = "opcional") public class Opcional implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idOpcional",nullable = false) private Short idOpcional; @Column(name = "descricao",nullable = false,length = 50) private String descricao; @ManyToMany(fetch = FetchType.LAZY,mappedBy = "opcionais") private List<Automovel> automoveis; //Métodos get/set/ } A anotação “@ManyToMany” indica um relacionamento de muitos para muitos, ela pode conter os atributos “fetch”, “cascade” e “mappedBy” O “mappedBy” está dizendo para o provedor de persistência que a associação foi mapeada na classe “Automóvel” (pois a anotação “@ManyToMany” está anotada para uma coleção do tipo “Automóvel”).na referência denominada “opcionais”. Agora, todas as classes do projeto podem ser mapeadas, pois, foi visto anotações de classes, atributos e associações. 24 5 OUTRAS ANOTAÇÕES Serão apresentadas algumas anotações que podem ser úteis durante esse projeto, ou até mesmo em outro projeto com requisitos diferentes. 5.1 CHAVE PRIMÁRIA COMPOSTA Em um modelo de banco de dados relacional podemos ter tabelas com mais de uma chave primária (chave primária composta). No JPA, definimos uma classe para conter os atributos referente a chave composta. @Embeddable public class TurmaId implements Serializable { private static final long serialVersionUID = 1L; @Column(name = "periodoLetivo",nullable = false,length = 10) private String periodoLetivo; @Column(name = "codigoTurma",nullable = false,length = 45) private String codigoTurma; //Métodos get/set } A anotação “@Embeddable” é utilizada para dizer que essa classe será incorporada a outra entidade. @Entity @Table(name = "turma") public class Turma implements Serializable { 25 private static final long serialVersionUID = 1L; @EmbeddedId private TurmaId id; @Column(name = "sala",nullable = false,length = 45) private String sala; //Métodos get/set } A anotação “@EmbeddedId” diz ao provedor de persistência que os atributos contidos referência anotada compõe a chave primária da entidade. Se existe uma coluna na chave primária composta que também é chave estrangeira (PFK), como o código da turma. Na associação é necessário colocar o mapeamento “@MapsId”. @MapsId("codigoTurma") @ManyToOne @JoinColumn(name=" codigoTurma") private Turma turma; 5.2 ANOTAÇÃO @NAMEDQUERY E anotação “@NamedQuery” permite definir consultas estáticas em JPQL (Java Pesistence Query Language). JPQL é usado para definir consultas em unidades persistentes independente do mecanismo de banco de dados. @Entity @Table(name = "cor") @NamedQuery(name = "todos",query = "select c from Cor c") public class Cor implements Serializable { } Nesse exemplo definimos uma consulta chamada “todos” que permite consultar todas as instâncias persistentes de “Cor”. O exemplo abaixo apresenta como referência a consulta definida pela “@NamedQuery”. Posteriormente, iremos aprender como realizar um CRUD (Create, Read, Update e Delete). 26 List<Cor> cores = em.createNamedQuery("todos", Cor.class).getResultList(); Podemos, definir várias consultas nomeadas através da anotação “@NamedQueries”. @Entity @Table(name = "cor") @NamedQueries({ @NamedQuery(name = "todos", query = "select c from Cor c"), @NamedQuery(name = "por_id", query = "select c from Cor c where c.idCor = :idCor")}) public class Cor implements Serializable { } Lembrando que você não pode ter consultas com nomes iguais no seu contexto de persistência. Na apostila gerenciamento dos objetos persistentes, será apresentado um pouco mais do JPQL. 6 UNIDADE DE PERSISTÊNCIA A unidade de persistência é utilizada para configurar informações sobre o provedor de persistência (JPA), tal como, identificar as classes que serão mapeadas como entidades e configurações de banco de dados. Para criar a unidade de persistência no Eclipse clique um arquivo XML denominado “persistence.xml” dentro da pasta “WEB-INF”. O conteúdo desse arquivo pode ser visto no quadro a seguir. <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="br.unipam.locadora" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>locadora</jta-data-source> <class>br.unipam.locadora.entity.Modelo</class> <class>br.unipam.locadora.entity.Cliente</class> <properties> <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.logging.parameters" value="true"/> </properties> </persistence-unit> </persistence> 27 No provedor de persistência “<provider>” podemos informar qual API irá fornecer uma implementação para o JPA. Iremos utilizar o EclipseLink da Eclipse Foundation como provedor de persistência. O JPA possui outras implementações, tais como, Hibernate da JBoss, TopLink da Oracle. Fica a sua escolha de qual implementação utilizar. Algumas configurações podem ser vistas no quadro a seguir: Configuração Descrição <provider> Define o provedor de persistência que implementa o JPA <class> Define as classes que estão mapeadas como entidades. <jta-data-source> É o nome do ponto de acesso para o banco de dados. eclipselink.logging.parameters eclipselink.logging.level Habilita os logs do provedor de persistência, útil para analisar os comandos SQL gerados pelo provedor. Após a criação da unidade de persistência será necessário criar o “jta-data- source”. Assim dentro da pasta “WEB-INF” clique um arquivo denominado “resources.xml”. Esse arquivo irá possuir informações para a conexão com o banco de dados. O valor fornecido o id do recurso “id="locadora"” deverá ser informa no arquivo de persistência através da tag “<jta-data-source>” <?xml version="1.0"?> <resources> <Resource id="locadora" type="javax.sql.DataSource"> jdbcDriver = com.mysql.jdbc.Driver jdbcUrl = jdbc:mysql://localhost:3306/locadora password = fepam userName = root </Resource> </resources> 7 GERENCIANDO OBJETOS PERSISTENTES 7.1 ENTITY MANAGER O Entity Manager é uma peça importante do JPA. Ele gerencia o estado e o ciclo de vida das entidades, bem como, consultas de entidades dentro do contexto de persistência. O 28 Entity Manager é responsável por criar, remover e atualizar instâncias de entidades persistentes e consultarentidades pela chave primária ou por consultas customizadas. A Tabela a seguir apresenta alguns métodos do Entity Manager. Método Descrição void persist(Object object) Permite adicionar uma instância ao contexto de persistência. void merge(Object object) Permite alterar o estado de um objeto no contexto de persistência. void remove(Object object) Permite excluir uma instância do contexto de persistência. O Entity Manager é uma interface implementada pelo provedor de persistência que irá gerar e executar comandos SQL. Para obter a implementação dessa interface, existe duas formas: Gerenciado pelo contêiner: o contêiner (Servlet, EJB, WebServices, entre outros) é responsável por obter uma instância do Entity Manager e gerenciar o seu ciclo de vida (controlar transações e abrir e fechar o Entity Manager, por exemplo).; Gerenciado pela aplicação: sua aplicação é responsável por obter uma instância do Entity Manager e gerenciar o seu ciclo de vida (controlar transações e abrir e fechar o Entity Manager, por exemplo). 7.1.1 Entity Manager gerenciado pelo contêiner A anotação “@PersistenceContext” diz para o contêiner que ele deve injetar uma instância do provedor de persistência na referência Entity Manager e ele será responsável por gerenciar o ciclo de vida do Entity Manager. Essa anotação pode receber o atributo “unitName” para especificar o nome da unidade de persistência do “persistence.xml”. No arquivo “persistence.xml” devemos definir o atributo “transaction- type="JTA"”. 29 @PersistenceContext private EntityManager em; Quando o “EntityManager” é gerenciado pelo contêiner não precisamos preocupar com iniciar e fechar uma transação. Pois, o contêiner realiza essa tarefa para nós. public void save(Marca marca) { em.persist(marca); } 7.1.2 Entity Manager gerenciado pela aplicação Em um Entity Manager gerenciado pela aplicação usaremos uma fábrica para criar uma instância da implementação do Entity Manager. private EntityManager em = Persistence .createEntityManagerFactory("br.com.aula.javaweb-ejbPU") .createEntityManager(); Para criar uma instância do Entity Manager devemos passar o nome da unidade de persistência. Agora ao iniciar uma transação, a aplicação é responsável por gerenciar o contexto de persistência. public void salvar (Marca marca){ em.getTransaction().begin(); em.persist(marca); em.getTransaction().commit(); } 7.1.3 Contexto de persistência O contexto de persistência é um conjunto de instâncias de entidades persistentes de um dado momento para uma transação do usuário. No contexto de persistência não existem instâncias duplicadas, ou seja, se no contexto tiver uma instância de “Marca” com o 30 identificador igual “1”, não há nenhuma outra instância de “Marca” com identificador igual a “1” no contexto de persistência. Ao invocar o método “persist” do Entity Manager estamos adicionando uma instância ao contexto de persistência, caso ela não exista. Ao realizar uma consulta pela chave primária, Entity Manager verifica primeiramente se a instância não está no contexto de persistência. Assim, o contexto de persistência armazena todos os objetos persistentes, e ao fim da transação ele efetua as alterações necessárias no banco de dados. Os objetos apenas vivem no contexto de persistência durante a transação. A Figura 2 apresenta o ciclo de vida do contexto de persistência. Figura 1 - Ciclo de vida do contexto de persistência 8 JAVA PERSISTENCE QUERY LANGUAGE O Java Persistence Query Language (JPQL) é usado para definir consultas de entidades persistentes independente do banco de dados utilizado. A sintaxe do JPQL segue o Inicia uma transação de consultar saldo Contexto de persistência Objeto 1 Objeto 2 Objeto 3 Objeto 4 Servidor Web (Web Contêiner) Inicializa o contexto de persistência <Passo 1> <Passo 2> Descarrega os objetos persistentes <Passo 3> <Passo 4> Finaliza a transação 31 padrão do SQL (linguagem utilizada em banco de dados relacionais), a diferença é que o resultado SQL é obtido na forma de registros e colunas e o JPQL retorna uma instância ou um conjunto de instâncias. A sintaxe do JPQL é orientada a objetos, encapsulando a estrutura de consultas do banco de dados. Os desenvolvedores precisam saber a estrutura de classes de entidades e não a estrutura de tabelas. Figura 2 - Entendendo a conversão JPQL para SQL 8.1 CRIANDO CONSULTAS Através das classes apresentadas pela Figura 4, iremos realizar algumas consultas em JPQL. Figura 3 - Classes para criação de consultas JPQL A Tabela 2 apresenta algumas consultas com JPQL. Todos os nomes utilizados para montagem da consulta são referentes aos nomes das classes e atributos e não o nome das tabelas e colunas do seu banco de dados. Entity Manager Comando JPQL: select c from MinhaClasse as c Comando SQL: select * from MinhaTabela as c Registros da tabela “MinhaTabela” Objetos do tipo “MinhaClasse” 32 Consulta Descrição Select c from Marca c Seleciona as instâncias persistentes de Marca. Essa consulta pode retornar uma instância ou uma coleção de Marcas Select c.descricao from Marca c Seleciona uma String ou uma coleção de Strings referente à descrição dos objetos Marca. Select c from Marca c where c.descricao = ‘Fiat’ Seleciona as instâncias persistentes de Marca que possui a descrição igual a “Fiat”. Select distinct c.descricao from Marca c Seleciona uma String ou uma coleção de Strings não repetidas, referentes à descrição dos objetos Marca. Select count(c) from Marca c Retorna a quantidade de instâncias persistentes de Marca. Select c from Marca c join fetch c.modelos m Retorna as marcas que estão associadas com o atributo “modelos”. A instrução “fetch” diz para carregar os objetos persistentes no atributo. Select m from Modelo m join fetch m.marca c where c.descricao = :descricao Retorna todos os Modelos que possuem a uma instância de marca com a descrição repassada. O “:descricao” indica um parâmetro será repassado em tempo de execução. Tabela 1 - Consultas JPQL 8.2 ESTRUTURA BÁSICA Em uma consulta JPQL segue a seguinte estrutura: SELECT < expressão > FROM < expressão > [WHERE < expressão >] [ORDER BY < expressão >] 33 [GROUP BY < expressão >] [HAVING < expressão >] 8.2.1 Where A cláusula where pode possuir os seguintes operadores de comparação: =, >, >=, <, <=, <>, [NOT] BETWEEN, [NOT] LIKE, [NOT] IN, IS [NOT] NULL, IS [NOT] EMPTY. 8.2.2 Outras consultas A Oracle disponibiliza em seu site toda a estrutura para construção de consultas em JPQL, acesso o site http://docs.oracle.com/cd/E17904_01/apirefs.1111/e13946/ejb3_langref.html para obter mais dicas sobre a linguagem JPQL. 8.3 MÉTODOS PARA CRIAR CONSULTAS O JPA 2.0 oferece quatro tipos de criação de consultas, com propósitos diferentes: Dynamic queries: consiste em uma consulta JPQL dinamicamente especificada em tempo de execução; Named queries: são consultas estáticas e imutáveis, definidas pela anotação “@NamedQuery”; Native queries: consiste em uma consulta utilizando a linguagem SQL nativa; Criteria API: é um novo conceito de criação de consultas através de uma API orientada a objetos. A interface Entity Managerfornece vários métodos para a criação de consultas. Esses métodos retornam uma interface Query ou TypedQuery. A interface Query é utilizadas quando o tipo do resultado é Object, e TypedQuery é usando quando o tipo do resultado é determinado por você. 34 Nessa apostila, veremos apenas criação de consultas com JPQL, então veremos apenas criação de Dynamic queries e Named queries. 8.3.1 Named Queries Através da anotação “@NamedQuery” podemos definir consultas estáticas dentro das nossas classes de entidades. @Entity @Table(name = "marca",schema = "javaweb") @NamedQueries({@NamedQuery(name = "marca.findAll", query = "select m from Marca m")}) public class Marca implements Serializable { } Uma Named query uma vez criada, não é possível altera-la em tempo de execução. Mas é possível criar uma Named query parametrizada. @Entity @Table(name = "marca",schema = "javaweb") @NamedQueries({@NamedQuery(name = "marca.findById", query = "select m from Marca m where m.idMarca = :idMarca")}) public class Marca implements Serializable { } Através de uma instância do Entity Manager (“em”), podemos criar uma consulta a partir de uma Named query invocando o método “createNamedQuery”: TypedQuery<Marca> marcaQuery = em.createNamedQuery("marca.findAll", Marca.class); Uma TypedQuery ao ser executada irá retornar instâncias do tipo “Marca”. Podemos também definir uma Query, que irá retornar instâncias do tipo “Object”, sendo necessário realizar um cast (conversão) para o tipo “Marca”. Query Query = em.createNamedQuery("marca.findAll"); 35 8.3.2 Dynamic Queries As Dynamic queries podem ser criadas dinamicamente em tempo de execução, invocando o método “createQuery” de uma instância do Entity Manager. TypedQuery<Cor> corQuery = em.createQuery("select c from Cor c", Cor.class); 8.3.3 Invocando uma consulta Ao definir uma consulta, iremos dizer ao Entity Manager para ele trazer as instâncias de acordo com a consulta. O JPA fornece dois métodos: getSingleResult(): retorna apenas uma instância; getResultList(): retorna uma coleção de instâncias. Esses métodos são invocados a partir de uma instância de Query ou TypedQuery. Veja um exemplo do “getResultList” em um objeto TypedQuery. TypedQuery<Cor> corQuery = em.createQuery("select c from Cor c", Cor.class); List<Cor> cores = corQuery.getResultList(); Veja um exemplo do “getSingleResult” em um objeto TypedQuery. TypedQuery<Cor> corQuery = em.createQuery("select c from Cor c where c.idCor = 1", Cor.class); Cor cor = corQuery.getSingleResult(); Conforme dito anteriormente o objeto Query é utilizado quando é necessário retornar uma instância do tipo Object. Query corQuery = em.createQuery("select c from Cor c where c.idCor = 1"); Object object = corQuery.getSingleResult(); 36 8.3.4 Passagem de parâmetros Em Named queries e Dynamic queries podemos passar parâmetros em tempo de execução. Para criar um parâmetro em uma consulta utilizamos os “:” (dois pontos) seguido do nome do parâmetro. Através do método “setParameter(nome,valor)” inserimos o parâmetro em nossa consulta. TypedQuery<Cor> corQuery = em.createQuery("select c from Cor c where c.idCor = :idCor", Cor.class); corQuery.setParameter("idCor", 1); Cor cor = corQuery.getSingleResult(); REFERÊNCIAS BAUER, Christian, KING, Gavin. Java Persistence com Hibernate. Rio de Janeiro: Ciência Moderna, 2007. GONCALVES, Antonio. Beginning Java™ EE 6 Platform with GlassFish™ 3. 2. ed. New York: Apress, 2010. ORACLE. The Java EE 6 Tutorial. Disponível em: <http://docs.oracle.com/javaee/6/tutorial/doc/>. Acesso em: 20 jan. 2014.
Compartilhar