Criando e executando consultas Formas de criar consultas 1 Formas de consultas • Hibernate Query Language (HQL), e um subconjunto do padrão JPA QL (Java Persistence API Query Language : session.createQuery("from Category c where c.name like 'Laptop%'"); entityManager.createQuery("select c from Category c where c.name like 'Laptop%'“ ); • Criteria API para consulta por critério (QBC) e consulta por exemplo (QBE): session.createCriteria(Category.class).add( Restrictions.like("name", "Laptop%") ); • SQL direto com ou sem mapeamento automático do resultsets para objeto. session.createSQLQuery( "select {c.*} from CATEGORY {c} where NAME like 'Laptop%'").addEntity("c", Category.class); 2 Preparando uma consulta • As interfaces org.hibernate.Query e org.hibernate.Criteria possuem inúmeros métodos para controlar a execução de uma consulta. • Query provê métodos para atribuir valores para parâmetros de consulta. • Para executar uma consulta em uma aplicação é necessário obter uma instância de uma destas interfaces utilizando a Session. Query hqlQuery = session.createQuery("from Event"); 3 Associação <one-to-many> • Uma associação <um-para-muitos> liga as tabelas de duas classes através de uma chave estrangeira sem intervensão nas tabelas. • Este mapeamento perde certa semântica para uma coleção normal Java: – Uma instância que contem uma classe entidade não pode pertencer a mais de uma instância de coleção. – Uma instância que contem uma classe entidade não pode aparecer em mais de um valor de um índice de coleção. • Uma associação de Estados e Municípios requer a existência de uma coluna de chave estrangeira e a possibilidade de uma coluna índice para a tabela Municípios. 4 <one-to-many class="ClassName" not-found="ignore|exception" entity-name="EntityName" node="element-name" embed-xml="true|false" /> • class (obrigatório): O nome da classe associada • not-found (opcional): Especifica como colocar em cache identificadores que referenciam as linhas inexistentes devem ser manipuladas. ignore tratará uma linha inexistente como uma associação nula. • entity-name (opcional): O nome da entidade classe associada, como uma classe alternativa. 5 Exemplo <hibernate-mapping> <class name="exemploestadolista.Estado" table="Estados"> <id name="ibge" column="IBGE"> </id> <property name="sigla"/> <property name="nome"/> <property name="area"/> <set name="municipios" table="municipios"> <key column="uf"/> <one-to-many class="exemploestadolista.Municipio" /> </set> </class> </hibernate-mapping> 6 Limitando a quantidade de respostas Query consulta = session.createQuery("from Estado order by sigla asc"); consulta.setMaxResults(10); Apresenta um conjunto com 10 elementos 7 Utiliza SQL e limitador Query consulta = session.createSQLQuery("select {e.*} from estados {e} order by {e.sigla}"). addEntity("e",Estado.class); consulta.setFirstResult(5); consulta.setMaxResults(10); Utiliza expressão SQL. Inicia o resultado no quinto elemento e apresenta 10 registros. 8 Utiliza Criteria Query consulta = session .createQuery(" from Estado order by sigla asc").setMaxResults(10); Criteria crit = session.createCriteria(Estado.class) .addOrder(Order.desc("sigla")) .setFirstResult(5) .setMaxResults(6); List relEstados = crit.list(); 9 Consulta com parâmetro String consultaString = "from Estado uf where uf.sigla = :pesquisa"; String ufString = "PR"; Query consulta = session.createQuery(consultaString).setString ("pesquisa", ufString); 10 HQL Hibernate Query Language Caio Nakashima [email protected] [email protected] 11 HQL • Hibernate é equipado com uma linguagem de consulta extremamente poderosa que (intencionalmente) é muito parecida com SQL. • HQL é completamente orientado a objetos, entendendo noções como herança, polifomorfismo e associação. • Consultas são case-insensitive (não sensíveis à letra), com exceção de nomes para as classes e propriedades Java. • Assim SeleCT tem o mesmo significado que sELEct e SELECT mas org.hibernate.eg.FOO não é igual a org.hibernate.eg.Foo e foo.barSet não é igual a not foo.BARSET. 12 Cláusula FROM • A mais simples consulta Hibernate é: from eg.Cat • Que retorna todas as instâncias da classe Cat. Não é necessário qualificar o nome da classe, desde que a auto importação é o padrão. Assim geralmente escreve-se: from Cat • Muitas vezes, é necessário atribuir uma alias, desde que deseja-se referir ao Cat em outras partes da consulta. from Cat as cat 13 Cláusula FROM (2) • Esta consulta atribui para a instância Cat um alias cat, assim pode-se utiliza-lo em outras partes da expressão de consulta. A palavra chave AS é opcional, assim pode-se escrever também: from Cat cat • Pode-se utilizar múltiplas classes, resultando um produto cartesiano ou um "cross" join. from Formula, Parameter from Formula as form, Parameter as param • É considerado uma boa prática nomear alias de consulta utilizando a primeira letra em minúscula, sendo consistente com o padrão Java para nomear variáveis locais. 14 Associações e Junções • Pode-se também associar aliases para entidades associadas ou também para elementos de uma coleção de valores utilizando JOIN. • from Cat as cat inner join cat.mate as mate left outer join cat.kittens as kitten • from Cat as cat left join cat.mate.kittens as kittens • from Formula form full join form.parameter param 15 Associações e Junções • Os tipos de junções (joins) suportados são emprestados do SQL ANSI: – – – – inner join left outer join right outer join full join • As construções inner join, left outer join e right outer join podem ser abreviadas. from Cat as cat join cat.mate as mate left join cat.kittens as kitten 16 Fetching strategies • Em um acesso tradicional aos dados, pode-se pegar todos dos dados requeridos para um processo em particular para uma consulta SQL simples, contando com a vantagem de junções internas ou externas (inner or outer joins) para recuperar as entidades relacionadas. • Algumas primitivas implementadas no modelo ORM (object/relational mapping) para pegar "pedaços" de dados com inúmeras requisições para pequenos pedaços de dados em resposta das aplicações navegando um grafo de objetos persistentes, não é uma forma eficiente de utilização das capacidades de junção (join) do banco de dados. 17 • Esta estratégia de acesso a dados é pobre por natureza. • Uma das maiores dificuldades em ORM é prover um acesso eficiente para os dados relacionais, dando uma aplicação que prefere tratar os dados como um objeto de grafo. • Para os tipos mais comuns de aplicações (multiusuário, distribuído, web e aplicações coorporativas), a recuperação de objetos utilizando muitos acessos ao banco de dados não é aceitável. Será discutido que as ferramentas devem enfatizar o R em ORM para a extensão maior que a tradicional. 18 • O problema de pegar objetos de grafos eficientemente, com acesso mínimo para o banco de dados, tem freqüentemente associando com o provimento ao nível de associação da estratégia de capturar um meta dados específico do mapeamento de associação. • O problema com esta solução é que cada pedaço do código que utiliza um requisito de entidade um conjunto diferente de objetos associados. Mas isto não é suficiente. • É necessário um suporte para refino da estratégia de execução da associação de captura. • Hibernate suporta as duas estratégias, que permite especificar uma estratégia padrão de captura no arquivo de mapeamento e então sobre escrever em tempo de execução no código. 19 • Hibernate permite escolher entre quarto estratégia de captura para qualquer associação, nos metadados de associação e em tempo de execução: • Immediate fetching - Captura Imediata – O objeto associado é capturado imediatamente, utilizando uma leitura em banco de dados seqüencial (cache). • Lazy fetching - Captura preguiçosa – O objeto associado ou coleção é capturado de "forma preguiçosa", quando é acessado. Resultada é uma nova requisição para o banco de dados (a não ser que o objeto associado esteja no cache). 20 • Eager fetching - Captura urgente – Um objeto associado ou coleção é capturado junto com o objeto proprietário, utilizando um outer join SQL, e nenhum outra requisição ao banco de dados é requerida. • Batch fetching - Captura em Lote – Esta abordagem pode ser utilizada para melhorar a performance da captura "preguiçosa" recuperando objetos ou coleções em lote, quando uma uma associação "preguiçosa" é acessada. – Captura em lote pode ser utilizado para melhorar a performance da captura imediata. 21 Immediate fetching (captura imediata) • Captura associativa imediata ocorre para recuperar uma entidade do banco de dados e então recuperar imediatamente outra entidade associada ou entidades em uma requisição futura do banco de dados ou do cache. • Captura imediata não é uma estratégia captura eficiente a não ser que espere que as entidades associadas estejam quase sempre no cache. 22 Lazy fetching (captura preguiçosa) • Quando um cliente requisita uma entidade e seu grafo de objetos associdado do banco de dados, não é usualmente necessário recuperar todo o grafo de todos os objetos associados (indiretamente). • Não se deseja carregar todo o banco de dados para a memória de uma vez, por exemplo, carregar um Pedido simples, não deve disparar uma carga de todos os itens do pedido. • Lazy fetching permite ao programador decidir quantos grafos de objetos serão carregados no primeiro acesso ao banco de dados e quais associações devem ser carregadas somente quando forem acessadas pela primeira vez. 23 Lazy fetching (cont.) • Lazy fetching é um conceito fundamental em persistência de objetos e o primeiro passo para obter uma performance aceitável. • Recomenda-se que, para começar com todas as associações sejam configurados para lazy ou talvez para batched lazy carregamento no arquivo de mapeamento. • Esta estratégia pode ser carregada (definida) em tempo de execução por consultas que forçam uma carga urgente. 24 Eager (outer join) fetching • Carga associada preguiçosa pode ajudar a reduzir a carga no banco de dados e é geralmente uma boa estratégia padrão. • Porém, é algo parecido como um "chute no escuro" assim como uma otimização de performance. • Carga urgente permite explicitamente especificar qual objeto associado deve ser carregado junto com o objeto referenciado. • Hibernate pode então retornar o objeto associado em uma requisição simples no banco de dados, utilizando um SQL OUTER JOIN. 25 Eager (outer join) fetching • Otimização de performance no Hibernate geralmente envolve um uso discreto da carga urgente para uma transação em particular. • Desta forma, mesmo que padrão a carga urgente pode ser declarada no arquivo de mapeamento, é mais comum para uma utilização específica desta estratégia em tempo de execução para uma HQL particular ou critério de consulta. 26 Batch fetching • Carga em lote não é estritamente uma estratégia de carga associada; é uma técnica que pode ajudar a melhorar a performance da carga preguiçosa ou carga imediata. • Geralmente, quando se carrega um objeto ou uma coleção, a cláusula WHERE do SQL especifica o identificador do objeto ou os objetos que possuem a coleção. • Se a carga em lote estiver habilitada, Hibernate procura ver o que outras instâncias de proxie ou coleções não inicializadas são referenciadas na seção corrente e tenta carrega-los ao mesmo tempo especificando múltiplos valores identificadores na clásula WHERE. 27 • Carga urgente é geralmente mais rápida. • Carga em batch é mais fácila para os usuários inexperientes que desejam arquivar com uma performance aceitável com Hibernate sem ter que pensar muito sobre o que SQL executará. 28 Selecionando uma estratégia de carga no mapeamento • Hibernate permite selecionar associação padrão para estratégia de carga especificando atributos nos metadados de mapeamento. • Pode-se carregar uma estratégia padrão utilizando características de consulta do Hibernate. • A wrinkle in Hibernate’s mapping format means that collection mappings function slightly differently than single-point associations; so, we’ll cover the two cases separately. • Let’s first consider both ends of the bidirectional association between Bid and Item. 29 • Uma junção "fetch" permite associações ou coleções de valores serem inicializadas por seus objetos pai, utilizando uma seleção simples. • É útil particularmente em caso de uma coleção (collection). • É eficiente para sobre escrever um outer join e lazy declarations do arquivo de mapeamento para associações e coleções. from Cat as cat inner join fetch cat.mate left join fetch cat.kittens 30 • Um fetch join geralmente não necessita atribuir um alias, por que os objetos associados não deve ser utilizado na cláusula where ou qualquer outra cláusula. • Objetos associados não retornam diretamente em resultados de uma consulta. • Por outro lado, podem ser acessados por objetos pai. • A única razão que se necessita um alias se existir um join fetching recursivo para uma coleção futura. 31 from Cat as cat inner join fetch cat.mate left join fetch cat.kittens child left join fetch child.kittens • Prestar atenção que uma construção com fetch não deve ser utilizado com consultas chamadas utilizando scroll() ou iterate(). • Nem o fetch pode ser utilizado junto com setMaxResults() ou setFirstResult(). 32 Produto Cartesiano • É possível criar um produto cartesiano juntando mais de uma coleção de em uma consulta, assim deve-se tomar cuidado neste caso. – Juntando múltiplas coleções pode resultar em resultados inesperados de um mapeamento mal feito. • Se utilizar a propriedade lazy fetching com a instrumentalização bytecode, é possível forçar o Hibernate a percorrer a propriedade lazy imediatamente na primeira consulta utilizando todas as propriedades de navegação. from Document fetch all properties order by name from Document doc fetch all properties where lower(doc.name) like '%cats%' 33