Baixe o app para aproveitar ainda mais
Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
* * Tópicos em Engenharia de Software II – 2011/2 Prof. Vitor Alcântara Batista * * Introdução Arquitetura Mapeamento de Entidades Mapeamento de Associações Persistindo objetos Consultando objetos * * Java Persistence API É um padrão definido pelo JCP para trabalhar com persistência de dados. O líder a especificação foi Gavin King, o criador do Hibernate. Existem várias implementações disponíveis no mercado. Hibernate, SAP Netweaver AS, TopLink, EclipseLink, Open,JPA, Kodo, JPOX, Amber, entre outras... * * Hibernate é um framework de mapeamento Objeto/Relacional para Java e .NET(NHibernate) Oferece serviços para consulta e recuperação de dados Objetivo: liberar o desenvolvedor de grande parte da programação relacionada a persistência de dados Suporte aos principais SGDBs * * Projeto Hibernate Mantido atualmente pelo JBoss Inc. Projeto Open-source Adotado por muitos projetos no mundo inteiro Versão 3 foi base para a especificação de persistência da JPA Hibernate implementa a JPA. * * * * Principais componentes Configuration SessionFactory Session Query Criteria Configuração * * org.hibernate.cfg.Configuration Classe responsável por carregar toda a configuração do hibernate Mapeamento de classes Configurações de banco de dados Pode ser criado a partir de arquivos de configuração hibernate.cfg.xml hibernate.properties Pode ter suas propriedades alteradas em tempo de execução Fábrica de SessionFactory * * org.hibernate.SessionFactory Fábrica responsável pela criação das sessões Cache dos mapeamentos compilados Possui um ciclo de vida longo, geralmente durante todo o período de atividade da aplicação É threadsafe (imutável) para uma única instância de banco de dados. * * org.hibernate.Session Representa uma conversação entre a aplicação e o banco de dados (BD) Possui um tempo de vida curto, geralmente associado a uma única transação com o BD Responsável por quase todos os métodos de persistência Fábrica de transações * * Estados de uma instância de objeto: Transiente: A instância não está, e nunca esteve associada a um contexto de persistência. O objeto não possui identificador (chave primária). Persistente: A instância está associada a um contexto de persistência. Possui identificador. Detached: A instância já esteve associada com um contexto de persistência, porém o contexto foi fechado ou a instância foi serializada por outro contexto. Removed: A instância está marcada para ser excluída, mas ainda não foi excluída. * * * * org.hibernate.Query Interface utilizada para pesquisas no BD Disponível para pesquisas utilizando SQL HQL Oferece métodos de paginação de resultados Parametrização de restrições na cláusula WHERE * * org.hibernate.Criteria Interface utilizada para pesquisas no BD Semelhante ao Query, mas utiliza uma estrutura de classes para representar a pesquisa Ex: List cats = session.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") .addOrder( Order.asc("name") ) .addOrder( Order.desc("age") ) .setMaxResults(50) .list(); * * hibernate.cfg.xml Contém informações sobre os arquivos de mapeamento Pode conter as informações necessárias para a conexão do banco de dados Deve estar no classpath O nome do arquivo pode ser configurado hibernate.properties Pode conter as informações de configuração da conexão e banco de dados Deve estar no classpath * * Mapeamento pode ser feito em arquivos xml separados do código fonte Pode ser feito com tags xDoclet no código fonte Pode ser feito com Annotations do Java 1.5 e Hibernate 3 * * Entidades: “Tipicamente” representam uma tabela no banco de dados. Cada instância de uma entidade corresponde a uma linha na tabela. Seguindo os padrões da JPA cada entidade DEVE atender os requisitos: Ser anotada coma anotação @Entity. Deve ter um construtor sem argumentos, público ou protegido. Não pode ser declarada final. Nenhum método ou variável de instância pode ser declarada como final. Variáveis de instância persistentes não devem ser declaradas públicas e só podem ser acessadas pelos métodos da classe. * * Uma Entidade é mapeada com a anotação @Entity Pode ser definido um nome para a tabela do banco de dados através do atributo name da anotação. Um objeto que não é uma entidade, mas que tem atributos persistentes ou informações de mapeamento, deve ser mapeado com a anotação @MappedSuperclass Objetos mapeados com a anotação @MappedSuperclass não podem ser pesquisados no banco, ou seja, não existe uma tabela para aquele objeto. A anotação @MappedSuperclass é utilizada para hierarquias de objetos. * * Entidades que extendem não-Entidades ao serem salvas, ignoram os dados da superclasse, a não ser que a superclasse utilize a anotação @MappedSuperclass Ou seja, os dados da superclasse são transientes e nunca serão persistentes. * * Como anotar a entidade import javax.persistence.Entity; @Entity public class Aluno { } * * * * Existem 3 estratégias de mapeamento de polimorfismo Uma tabela para toda a hierarquia de classes Uma tabela por classe concreta Uma tabela por subclasse Flexibilidade Desempenho * * Uma tabela para toda a hierarquia de classes Toda a hierarquia de classes é representada por uma única tabela no banco de dados Propriedades de uma subclasse específica não podem ser anotadas com a anotação @NotNull Utiliza a anotação @DiscriminatorColumn para identificar a instância * * Uma tabela para toda a hierarquia de classe @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name=“TYPE", discriminatorType=DiscriminatorType.STRING) public class Person { …} @Entity @DiscriminatorValue(“EMP") public class Employee { … } @Entity @DiscriminatorValue(“STU") public class Student { … } * * Uma tabela para toda a hierarquia de classe: @Inheritance e @DiscriminatorColumn só devem ser utilizados no topo da hierarquia. Caso não seja informado um name para o DiscriminatorType o default é DTYPE Caso não seja informado um valor para o DiscriminatorValue o default é o nome da entidade, conforme definido na anotação @Entity. * * Uma tabela por classe concreta Cada classe concreta será armazenada em uma tabela distinta * * Uma tabela por classe concreta A classe abstrata Person não é mapeada As sub-classes são mapeadas como uma classe qualquer @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Person { … } @Entity public class Student extends Person { … } @Entity public class Employee extends Person { … } * * Uma tabela por classe concreta Cada classe será armazenada em uma tabela Estratégia mais “orientada à objeto” Necessita de mais joins entre tabelas para recuperar dados. Não suporta muito bem associações polimórficas. * * Uma tabela por classe * * Uma tabela por classe @Entity @Inheritance(strategy=InheritanceType.JOINED) public abstract class Person { …} @Entity public class Employee { … } @Entity @PrimaryKeyJoinColumn(name=“Person_ID") public class Student { … } * * Uma tabela por classe Cada classe será armazenada em uma tabela, inclusive a classe pai, sendo ela abstrata ou não. Necessita de um único join para recuperar os dados. Pode impactar no desempenho de uma aplicação devido ao número de joins que podem ser feitos em uma hierarquia completa. * * A primeira estratégia é a mais simples mas restringe a utilização de not-null Utilizado quando a principal diferença entre as diferentes sub-classes é seu comportamento, possuindo quase o mesmo conjunto de propriedades A segunda resolve o problema do not-null e da diferença entre o conjunto de propriedades Mas apresenta problema com associação polimórfica A terceira é a mais flexível Permite associações com classes abstratas Mas necessita de mais joins para recuperar dados * * A anotação @Id define o identificador único da classe Toda classe deve declarar um identificador obrigatoriamente A anotação @GeneratedValue é utilizada para definir a forma com que o id será gerado. @Id @GeneratedValue (strategy=GenerationType.AUTO) public Long getId(){} * * toda entidade é herdeira de ObjetoPersistente, que contém o Identificador @MappedSuperclass public abstract class ObjetoPersistente implements Comparable<Object> { private Long id; @Id @GeneratedValue public final Long getId() @Entity public final class Usuário extends EntidadePersistente * * Tipos de associações: 1 – 1 1 – N (composição) 1 – N N - N * * A entidade que possui a chave estrangeira é responsável pela associação (a associação é persistida quando o objeto é persistido). @OneToOne @JoinColumn public Endereço getEndereco(){…} @OneToOne(mappedBy=“endereco”) public Pessoa getPessoa(){…} * * Uma tabela é criada com o nome de PessoaEndereco e em cada linha armazenará o id da Pessoa e o id do Endereço nas colunas pessoa_fk e endereco_fk,respectivamente. @OneToOne (cascade=CascadeType.ALL) @JoinTable(name=“PessoaEndereco", joinColumns = @JoinColumn(name = “pessoa_fk"), inverseJoinColumns = @JoinColumn(name = “endereco_fk") ) public Endereço getEndereco(){…} @OneToOne(mappedBy=“endereco”) public Pessoa getPessoa(){…} * * Cuidado com o nome das chaves, eles são os responsáveis por tornar a associação bidirecional As opções de cascade devem ser feitas de acordo com o tipo de associação Se existir uma composição entre Pessoa e Dependente, a opção de cascade do lado de Pessoa deveria ser “all-delete-orphan ” Isso vincularia o ciclo de vida de Dependente a Pessoa. @OneToMany(mappedBy=“responsavel“) public Collection getDependetes(){…} @ManyToOne(cascade=CascadeType.ALL) @JoinColumn @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN) public Pessoa getResponsavel(){…} * * Também é possível fazer o mapeamento ManyToOne e OneToMany utilizando uma tabela secundária. O comportamento é o mesmo do mapeamento OneToOne com tabela secundária. Este caso é recomendado quando o relacionamento é unidirecional em casos OneToMany. @OneToMany @JoinTable(name=“Pessoa_Dependente", joinColumns = @JoinColumn(name = “pessoa_id"), inverseJoinColumns = @JoinColumn(name =“dependente_id") ) public Collection getDependetes(){…} @Entity public class Dependente { … //Não existe o atributo pessoa ... } * * Em associações 1 – N SEMPRE o lado N comandará a associação A associação é persistida quando Dependente for persistido. Esta regra é uma boa prática, pois é otimizada e em geral executará apenas uma ação via cascade ao invés de N. @OneToMany(mappedBy=“responsavel") public Collection getDependetes(){…} @ManyToOne @JoinColumn(name=“PESSOA_DEP") public Pessoa getResponsavel(){…} * * Em mapeamento many-to-many é importante utilizar o mappedBy para indicar qual lado manda na relação. Cascade para deleção deve ser utilizado com cuidado, já que uma entidade com diversas associações pode ser apagada quando somente um das entidades associados for apagada. @ManyToMany(mappedBy=“pessoas") public Collection getFuncoes(){…} @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }) @JoinTable public Pessoa getPessoas(){…} * * Importância do cascade O cascade define a propagação das operações de persistência Importante para o ciclo de vida das entidades relacionadas Cascade mal planejado pode destruir uma aplicação Problemas de desempenho Perda de dados por cascade - CascadeType.Remove Deixar “lixo” no banco de dados * * Persist: Propaga a operação de persistência para os objetos associados se o método persist() é chamado ou se a entity é gerenciada. Merge: Propaga a operação de merge para os objetos associados se o método merge() é chamado ou se a entity é gerenciada. Remove: Propaga a operação de deleção para os objetos associados se o método delete() é chamado. Refresh: Propaga a operação de atualização para os objetos associados se o método refresh() é chamado. All:Todos os anteriores. * * Eager: Utiliza um outer join para recuperar os objetos associados quando o objeto base é carregado. Lazy: Carrega os objetos associados somente quando eles forem utilizados pelo objeto base. Relacionamentos OneToMany e ManyToMany têm por default o tipo de recuperação Lazy, enquanto os relacionamentos OneToOne e ManyToOne tem o tipo de recuperação Eager. @ManyToMany (fetch=FetchType.EAGER) * * Principais Interfaces do JPA EntityManagerFactory EntityManager EntityTransaction * * Fornece instâncias de EntityManager Todas as instâncias fornecidas, conectam num mesmo banco e são geradas, por padrão, com as mesmas configurações. A fábrica, usualmente, está associada à aplicação e tem o mesmo ciclo de vida dela * * private static EntityManagerFactory emf; emf = Persistence.createEntityManagerFactory("praxis"); <persistence-unit name="praxis"> <properties> <property name="hibernate.archive.autodetection“ value="class, hbm" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" /> <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost:9001/" /> <property name="hibernate.connection.username" value="sa" /> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="create-dropk" /> </properties> </persistence-unit> Arquivo persistence.xml * * Semelhante à classe Session do Hibernate. Utilizada para persistir, excluir, recuperar pelo ID e fazer consulta por objetos. Principais métodos persists(Object) remove(Object) find(Class<T>, Object) getReference(Class<T>, Object) createQuery(String) getTransaction() * * Persistindo um objeto Recuperando um objeto pelo ID EntityManager em = emf.createEntityManager(); Aluno a = new Aluno(); a.setNome("Vitor"); em.persist(a); EntityManager em = emf.createEntityManager(); Aluno a = em.find(Aluno.class, new Long(1)); * * Recuperando todos os objetos de uma classe Recuperando objetos de um tipo com filtro List<Aluno> alunos = em.createQuery("from Aluno").getResultList(); List<Pessoa> alunos = em.createQuery( "select nome from Aluno as aluno where aluno.nome = ?1") .setParameter(1, "Vitor") .getResultList(); Query q = em.createQuery("select nome from Aluno as aluno where aluno.nome = :nome"); q.setParameter(“nome”, “Vitor”); List<Pessoa> alunos = q.getResultList(); * * Só é necessário fazer joins quando deseja-se filtrar o resultado por um atributo de outra entidade. Ao recuperar um objeto, é possível navegar pelas associações e o hibernate recupera as instâncias associadas. * * HQL Consulta executada pelo Hibernate List<Pessoa> alunos = em.createQuery( "select aluno.nome from Aluno as aluno JOIN aluno.endereco as endereco where endereco.cidade = ?1“).setParameter(1, "BH“) .getResultList(); select aluno.nome from Aluno inner join Pessoa on Pessoa.id=Aluno.id inner join Endereco on Pessoa.id=Endereco.pessoa_id where Endereco.cidade=? * * Criar um novo projeto, configurar o Hibernate e mapear um modelo de Entidades. * * Criar código Java (uma nova classe executável) para reproduzir um conjunto de objetos. Executar consultas nesses objetos e mostrá-los no console
Compartilhar