Category Archives: Persistência
JPQL – Como criar query de DELETE com JOIN
E ai galera beleza?
Estou em um novo projeto muito legal, e me deparei com um problema, eu precisava fazer uma query para deletar uns dados no banco, só que pra selecionar exatamente oque eu precisava excluir era necessário utilizar joins, porém ao montar uma query parecida com essa:
delete from Queue q
where q.enabledMember = :enabledMember
and q.letter.eventReason.event.type = :eventType
and q.letter.eventReason.reason = :reason
Tomei o seguinte erro:
The entity abstract schema type declaration is malformed
Pesquisei um pouco na net e achei a seguinte solução, deletar a partir de um subselect, a query ficou assim:
delete from Queue q
where q in (select sq from Queue sq
where sq.enabledMember = :enabledMember
and sq.letter.eventReason.event.type = :eventType
and sq.letter.eventReason.reason = :reason )
Bom, é isso ai galera, espero que tenha ajudado 😀
Abraços!
Fonte: Jake Trent – JakeTrent.com
JPA2/Hibernate – Auto-incremento em colunas non-id (sem anotação @Id)
E ai galera beleza? hoje tive um problema ao tentar implementar:
@SequenceGenerator(name="MINHA_SEQUENCE", sequenceName="MINHA_SEQUENCE", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MINHA_SEQUENCE")
em uma coluna que não tinha @Id… simplesmente não estava criando a sequence, consequentemente, não gerava o valor automatico…
achei a seguinte solução: (não utiliza as anotações @SequenceGenerator
e @GeneratedValue
)
@Column(columnDefinition="serial")
@Generated(GenerationTime.INSERT)
testei no postgresql e funcionou perfeitamente!
Espero que ajude 😀 abraços !
Fonte: Sergey Vedernikov – Stackoverflow / axtavt – Stackoverflow
JBoss – Criando/Configurando um Datasource
E ai galera beleza, segue um tutorial de como criar um Datasource utilizando MySQL (ou qualquer outro Banco de Dados) no JBoss…
1. No arquivo JBOSS_HOME\standalone\configuration\standalone.xml :
(procure as linhas abaixo…)
…
<subsystem xmlns=”urn:jboss:domain:datasources:1.0″>
<datasources>
<datasource jndi-name=”java:jboss/datasources/ExampleDS” pool-name=”ExampleDS” enabled=”true” use-java-context=”true”>
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name=”h2″ module=”com.h2database.h2″>
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
…
Adicione as seguintes linhas após a tag </datasource>:
<datasource jta=”true” jndi-name=”java:jboss/datasources/seuDataSourceDS” pool-name=”seudatasource” enabled=”true” use-java-context=”true” use-ccm=”true”>
<connection-url>jdbc:mysql://localhost:3306/seubancodedados</connection-url>
<driver>mysql</driver>
<security>
<user-name>root</user-name>
<password>suasenha</password>
</security>
</datasource>
Adicione as seguintes linhas após a tag </driver>:
<driver name=”mysql” module=”com.mysql”>
<xa-datasource-class>com.mysql.jdbc.Driver</xa-datasource-class>
</driver>
2. Adicione o seu arquivo jar do driver do banco (mysql-connector-java-X.X.X-bin.jar
) na pasta JBOSS_HOME\modules\com\mysql\main (caso o diretorio mysql\main não exista crie-o).
3. Nesta mesma pasta crie o arquivo module.xml com o seguinte conteudo: (cuidado para não deixar nenhum espaço em branco no começo do conteudo do arquivo, pode dar problema!)
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="com.mysql">
<resources>
<resource-root path="mysql-connector-java-X.X.X-bin.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
Se estiver utilizando JPA/Hibernate adicione a seguinte linha no seu persistence.xml:
<jta-data-source>java:jboss/datasources/seuDataSourceDS</jta-data-source>
Bom espero que ajude, achei essa configuração indo atrás de um erro que tomei:
New missing/unsatisfied dependencies: service jboss.naming.context.java.jboss.datasources.XXXXX (missing) dependents: [service jboss.persistenceunit."..."]
Acredito que é a mesma regra para os outros bandos de dados (mudando as devidas informações)… See ya 😀
Spring Data JPA Avançado – Epecificações e queryDSL
Neste post eu gostaria de mergulhar dentro de alguns recursos e como eles poderiam lhe ajudar a simplificar a implementação da camada de acesso a dados ainda mais. A abstração do repositório Spring Data consiste de um modelo de programação baseado em interface, algumas classes de fábrica e um Spring namespace para facilmente configurar a infraestrutura. Uma interface de repositório típica se parece com isso:
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByEmailAddress(String emailAddress);
List<Customer> findByLastname(String lastname, Sort sort);
Page<Customer> findByFirstname(String firstname, Pageable pageable);
}
O primeiro método simplesmente espera encontrar um único cliente com um determinado endereço de email, o segundo método retorna todos os clientes com um determinado sobrenome e aplica-se a ordenação determinada ao resultado, enquanto o terceiro método retorna uma página de clientes. Para mais detalhes dê uma olhada neste artigo (inglês)
Embora essa abordagem seja realmente conveniente (você não precisa escrever uma única linha de implementação de código para ter as queries executadas) temos 2 desvantagens nisso: primeira, o número de métodos de consultas pode crescer para grandes aplicações por causa disso – e esse é o segundo ponto, as consultas definem um conjunto fixo de criterias. Para evitar essas 2 desvantagens, não seria legal se você pudesse chegar com um conjunto de atributos atômicos que você pudesse combinar dinamicamente para construir uma consulta?
Se você é uma usuário de JPA a muito tempo, você pode responder: não é pra isso que a API Criteria serve? Correto, então vamos dar uma olhada como se parece um exemplo de implementação de regra de negócio utilizando a API Criteria JPA. Esse é o caso de uso: nos aniversários deles nós queremos enviar um voucher para todos cliente de longa data. Como recuperaríamos aqueles com essa combinação?
Nós praticamente temos 2 partes para o predicate (atributo/predicado): o aniversário assim como o que nós chamamos de cliente-de-longa-data. Vamos assumir que isso significa que a criação da conta do cliente foi a pelo menos 2 anos atrás. Assim é como se pareceria a implementação utilizando a API Crieria JPA:
LocalDate today = new LocalDate();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Customer> query = builder.createQuery(Customer.class);
Root<Customer> root = query.from(Customer.class);
Predicate hasBirthday = builder.equal(root.get(Customer_.birthday), today);
Predicate isLongTermCustomer = builder.lessThan(root.get(Customer_.createdAt), today.minusYears(2);
query.where(builder.and(hasBirthday, isLongTermCustomer));
em.createQuery(query.select(root)).getResultList();
O que temos aqui? Criamos uma nova LocalDate por conveniência e seguimos com três linhas padrões para estabelecer as instâncias da infraestrutura JPA necessária. Então temos duas linhas construindo os atributos/predicados, uma para concatenar as duas e uma ultima para executar a consulta atual. Estamos usando classes de meta-modelagem introduzidas com JPA 2.0 e geradas pela API de Processamento de Anotações. O principal problema com este código é que os atributos não são fáceis de externalizar e reutilizar porque você precisa configurar o CriteriaBuilder, CriteriaQuery e o Root primeiro. Além da readaptação do código é tão pobre quanto é difícil de deduzir rapidamente a intenção do código à primeira vista.
Especificações
Para estar apto para definir atributos/predicados reutilizáveis nós introduzimos a interface de Especificação que é derivada dos conceitos introduzidos no livro Domain Driven Design de Eric Vans. Ele define uma especificação como um atributo sobre uma entidade a qual é exatamente o que nossa interface de especificação representa. Atualmente consiste em apenas um único método:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb);
}
então agora podemos facilmente utilizar uma classe utilitária como essa:
public CustomerSpecifications {
public static Specification<Customer> customerHasBirthday() {
return new Specification<Customer> {
public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) {
return cb.equal(root.get(Customer_.birthday), today);
}
};
}
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer> {
public Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb) {
return cb.lessThan(root.get(Customer_.createdAt), new LocalDate.minusYears(2));
}
};
}
}
Reconhecidamente, não é o código mais bonito do mundo, mas fornece nossa necessidade inicial muito bem: podemos nos referir a um conjunto de especificações atômicas. A próxima questão é: como vamos executar essas especificações? Para fazer isso, você simplesmente estende JpaSpecificationExecutor
na interface do seu repositório e assim “puxa” uma API para executar especificações:
public interface CustomerRepository extends JpaRepository<Customer>, JpaSpecificationExecutor {
// Seus métodos de consulta aqui!!!
}
Um cliente pode agora fazer:
customerRepository.findAll(hasBirthday());
customerRepository.findAll(isLongTermCustomer());
A implementação do repositório básico irá preparar o CriteriaQuery, Root e CriteriaBuilder para você, aplique o atributo/predicado criado por uma especificação determinada e execute a consulta. Mas nós não poderiamos apenas ter criado métodos simples de consulta para realizar isso? Correto, mas lembre-se do nossa segunda necessidade inicial. Nós queremos estar aptos para combinar livremente especificações atômicas para criar novos na hora. Para fazer isso nós temos especificações da classe utilitária que fornece os métodos and(…) e or(…) para concatenar especificações anatomicas. Temos também um where(…) que fornece uma doce semântica que faz a expressão mais legível. O exemplo do caso se uso que vimos no começo parece com isso:
customerRepository.findAll(where(customerHasBirthday()).and(isLongTermCustomer()));
Isto fica mais legível, melhorando tanto a legibilidade quanto fornecendo flexibilidade adicional comparado ao uso da API Criteria JPA sozinha. A única ressalva aqui é que subindo com a implementação da especificação requer algum esforço de codificação.
QueryDSL
Para curar essa dor um projeto open-source chamado Querydsl surgiu com uma abordagem bastante similar mas também diferente. Assim como a API Criteria JPA ela usa um processador de anotações Java 6 para gerar objetos meta-modelos mas produz uma API muito mais acessível. Outra coisa legal sobre o projeto, é que não tem suporte apenas para JPA, mas também aceita consultas Hibernate, JDO, Lucene, JDBC e até coleções simples.
Então para tê-lo instalado e rodando você adiciona o QueryDSL ao seu pom.xml
e configura o plugin APT plugin conforme abaixo:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
Isso irá fazer o seu build criar classes de consulta especiais – QCustomer
dentro do mesmo pacote no nosso caso.
QCustomer customer = QCustomer.customer;
LocalDate today = new LocalDate();
BooleanExpression customerHasBirthday = customer.birthday.eq(today);
BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));
Este não é apenas o Inglês quase fluente fora da caixa (?), o BooleanExpression
s, é mesmo reutilizável sem mais empacotamento do qual nos livra da especificação wrapper adicional (um pouco desagradável de implementar). Um plus adicional é que você tem o auto-complete de código da IDE a cada ponto do lado direito de atribuição, então customer. + CTRL + SPACE
listará todas as propriedades. customer.birthday. + CTRL + SPACE
listará todas as palavras-chave disponíveis e assim por diante. Para executar os atributos do QueryDSL você simplesmente estende QueryDslPredicateExecutor
ao seu repositório:
public interface CustomerRepository extends JpaRepository<Customer>, QueryDslPredicateExecutor {
// Seus métodos de consulta aqui!!!
}
Os clientes podem simplesmente fazer:
BooleanExpression customerHasBirthday = customer.birthday.eq(today);
BooleanExpression isLongTermCustomer = customer.createdAt.lt(today.minusYears(2));
customerRepository.findAll(customerHasBirthday.and(isLongTermCustomer));
Resumo
A abstração do repositório Spring Data JPA permite a execução de atributos/predicados ou via atributos API Criteria JPA wrapped dentro de um objeto de especificação ou via atributos QueryDSL. Para permitir essa funcionalidade você simplesmente deixa seu repositório extender JpaSpecificationExecutor ou QueryDslPredicateExecutor (você poderia até mesmo usar os 2 se você gostou). Veja que você precisa dos JAR’s do QueryDSL na classe no caso de você decidir pela abordagem do QueryDSL.
Mais uma coisa
Mais uma coisa legal sobre a abordagem do QueryDSL é que ela não está apenas disponível para os nossos repositórios JPA, mas para nosso apoio MongoDB também. A funcionalidade é inclusa apenas no release M2 do Spring Data MongoDB. Além de ambos módulos Mongo e JPA do Spring Data, são suportados na plataforma CloudFoundry. Veja os exemplos em cloudfoundry-samples wiki para iniciar em Spring Data e CloudFoundry.
Fonte: SpringSource – Oliver Gierke
Brincando com Generics: o BizarreGenericDao
Conversando com o Orseni Campos, ele me contou de uma sacada muito interessante que teve juntamente com seu colega Alexandre Bitencourt para resolver um clássico problema do generics: em tempo de execução você não consegue descobrir o tipo parametrizado que foi passado como argumento.
Em outras palavras, repare no código do Dao
genérico que foi discutido aqui (estou pulando a interface por questão de simplicidade):
public class Dao<T> { // ... public Dao(Session session, Class<T> persistentClass) { this .session = session; this .persistentClass = persistentClass; } } |
Aí, quando vamos criar um novo dao genérico:
Dao<Livro> dao = new Dao<Livro>(session, Livro. class ); |
Parece estranho ter de passar a Class que representa o livro, se eu já estou passando essa informação através do tipo parametrizado. Seria interessante fazer algo como:
public class Dao<T> { // ... public Dao(Session session) { this .session = session; this .persistentClass = T. class ; } } |
Isso não compila, essa informação (sobre quem é T
dentro de Dao
) não é armazenada em um .class
. O motivo é simples. Só existe uma classe Dao
, não importa como ela foi instânciada. Em outras palavras:
( new Dao<Autor>(session, Autor. class )).getClass() == ( new Dao<Livro>(session, Livro. class )).getClass() |
retorna true
. Então o problema é o seguinte: existe apenas uma classe, não importa quantas instâncias de tipo parametrizado diferentes você criar. Não faria sentido algum ter um método como clazz.getTypeArguments()
que te devolvesse uma array com os tipos parametrizados que tivessem sido usados na instanciação, já que só existe uma classe para todas as instâncias de diferentes tipos parametrizados. Isso se deve a erasure: em tempo de execução só sabemos que T
pode ser um filha de Object
, nesse caso.
Mas e se existisse mais de uma classe?
class AutorDao extends Dao<Autor> { } class LivroDao extends Dao<Livro> { } |
Obviamente (new LivroDao()).getClass() == (new AutorDao()).getClass()
retorna false
. Mais que isso, agora você consegue buscar por reflection qual é o parâmetro que foi passado na hora de estender a classe Dao
, já que AutorDao
e LivroDao
possuem essa informação em seus bytecodes:
Class clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ]; |
Então, se colocamos essa linha dentro da nossa classe mãe:
public class Dao<T> { // ... public Dao(Session session) { this .session = session; this .persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ]; } } |
Agora funciona caso utilizemos uma instância de uma filha de Dao
que tenha explicitado quem é T
. Bem, eu não gostei dessa solução porque nos obrigava a ter uma classe filha, mesmo que vazia, para cada entidade. Mas o Orseni e o Alexandre não desistiram. A proposta deles foi de declarar Dao
como abstrata, e na hora de instanciar:
Dao<Livro> dao = new Dao<Livro>(session){}; |
Repare o {}
! Esse código vai gerar uma classe anônima em tempo de compilação, e essa classe sem nome vai ser filha de Dao<Livro>
, e agora podemos pegar essa informação por reflection! Isso sim é gambiarra criatividade . Usar em produção? Acho que não seria elegante. Nem eles estão usando, mas foi um bonito desafio.
Fonte: Caelum – Paulo Silveira