Um guia para o módulo de dados DeltaSpike
1. Visão geral
Apache DeltaSpike é um projeto que fornece umcollection of CDI extensions para projetos Java; requer que uma implementação de CDI esteja disponível em tempo de execução.
Of course, it can work with the different implementation of CDI - JBoss Weld ou OpenWebBeans. Também é testado em muitos servidores de aplicativos.
Neste tutorial, vamos nos concentrar emone of the best known and useful – Data module.
2. Configuração do Módulo de Dados DeltaSpike
O módulo Apache DeltaSpike Data é usado parasimplify implementation of the repository pattern. Ele permitereducing a boilerplate code by providing centralized logic for queries creation and execution.
É muito semelhante ao projetoSpring Data. Para consultar um banco de dados, precisamos definir uma declaração de método (sem implementação) que segue a convenção de nomenclatura definida ou que contém a anotação@Query. A implementação será feita para nós pela extensão CDI.
Nas próximas subseções, vamos cobrir como configurar o módulo Apache DeltaSpike Data em nosso aplicativo.
2.1. Dependências necessárias
Para usar o módulo Apache DeltaSpike Data no aplicativo, precisamos configurar as dependências necessárias.
Quando o Maven é nossa ferramenta de construção, temos que usar:
org.apache.deltaspike.modules
deltaspike-data-module-api
1.8.2
compile
org.apache.deltaspike.modules
deltaspike-data-module-impl
1.8.2
runtime
Quando usamos o Gradle:
runtime 'org.apache.deltaspike.modules:deltaspike-data-module-impl'
compile 'org.apache.deltaspike.modules:deltaspike-data-module-api'
Os artefatos do módulo Apache DeltaSpike Data estão disponíveis no Maven Central:
Pararun an application with Data module, we also need a JPA and CDI implementations available at runtime.
Embora seja possível executar o Apache DeltaSpike no aplicativo Java SE, na maioria dos casos, ele será implementado no servidor de aplicativos (por exemplo, Wildfly ou WebSphere).
Os servidores de aplicativos têm suporte total a Java EE, então não precisamos fazer mais nada. No caso do aplicativo Java SE, precisamos fornecer essas implementações (por exemplo, adicionando dependências ao Hibernate e JBoss Weld).
A seguir, também abordaremos a configuração necessária paraEntityManager.
2.2. Configuração do Entity Manager
OData module requires EntityManager to be injected over CDI.
Podemos conseguir isso usando um produtor de CDI:
public class EntityManagerProducer {
@PersistenceContext(unitName = "primary")
private EntityManager entityManager;
@ApplicationScoped
@Produces
public EntityManager getEntityManager() {
return entityManager;
}
}
O código acima assume que temos uma unidade de persistência com o nomeprimary definida no arquivopersistence.xml.
Vejamos abaixo um exemplo de definição:
java:jboss/datasources/example-jee7-seedDS
A unidade de persistência em nosso exemplo usa o tipo de transação JTA, o que significa que temos que fornecer uma estratégia de transação que iremos usar.
2.3. Estratégia de Transação
In case we’re using JTA transaction type for our data source then we have to define Transaction Strategy that will be used in the Apache DeltaSpike repositories. Podemos fazer isso dentro do arquivoapache-deltaspike.properties (no diretórioMETA-INF):
globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy
Existem quatro tipos de estratégia de transação que podemos definir:
-
BeanManagedUserTransactionStrategy
-
ResourceLocalTransactionStrategy
-
ContainerManagedTransactionStrategy
-
EnvironmentAwareTransactionStrategy
Todos eles implementamorg.apache.deltaspike.jpa.spi.transaction.TransactionStrategy.
Esta foi a última parte da configuração necessária para o nosso módulo de dados.
A seguir, mostraremos como implementar as classes de padrão de repositório.
3. Classes de Repositório
Quando estamos usando o módulo de dados Apache DeltaSpike classeany abstract class or interface can become a repository.
All we have to do is toadd an @Repositoryannotation com um atributoforEntity que define a entidade JPA que nosso repositório deve manipular:
@Entity
public class User {
// ...
}
@Repository(forEntity = User.class)
public interface SimpleUserRepository {
// ...
}
ou com uma classe abstrata:
@Repository(forEntity = User.class)
public abstract class SimpleUserRepository {
// ...
}
O módulo de dados descobre classes (ou interfaces) com tal anotação e processará os métodos que estão dentro.
Existem poucas possibilidades para definir a consulta a ser executada. Cobriremos um por um em breve nas seções a seguir.
4. Consulta do nome do método
A primeira possibilidade paradefine a query is to use method name which follows a defined naming convention.
Parece abaixo:
(Entity|Optional|List|Stream) (prefix)(Property[Comparator]){Operator Property [Comparator]}
A seguir, vamos nos concentrar em cada parte desta definição.
4.1. Tipo de retorno
Oreturn type mainly defines how many objects our query might return. Não podemos definir o tipo de entidade única como um valor de retorno, caso nossa consulta possa retornar mais de um resultado.
O método a seguir lançará uma exceção no caso de haver mais de umUser com o nome fornecido:
public abstract User findByFirstName(String firstName);
O oposto não é verdade - podemos definir um valor de retorno comoCollection, embora o resultado seja apenas uma única entidade.
public abstract Collection findAnyByFirstName(String firstName);
O prefixo do nome do método que sugere um valor como um tipo de retorno (por exemplo,findAny) é suprimido no caso de definirmos o valor de retorno comoCollection.
A consulta acima retornará todos osUsers com um primeiro nome correspondendo até mesmo o prefixo do nome do método sugere algo diferente.
Tais combinações (tipo de retornoCollection e um prefixo que sugere um único valor de retorno) devem ser evitadas porque o código se torna não intuitivo e difícil de entender.
A próxima seção mostra mais detalhes sobre o prefixo do nome do método.
4.2. Prefixo para Método de Consulta
Prefix defines the action we want to execute on the repository. O mais útil é encontrar entidades que correspondam a determinados critérios de pesquisa.
Existem muitos prefixos para esta ação comofindBy,findAny,findAll. Para a lista detalhada, verifique o Apache DeltaSpikedocumentation oficial:
public abstract User findAnyByLastName(String lastName);
No entanto, também existemother method templates which are used for counting and removing entities. Podemoscount todas as linhas de uma tabela:
public abstract int count();
Além disso, existe o modelo de métodoremove que podemos adicionar em nosso repositório:
public abstract void remove(User user);
O suporte para prefixos de métodocountByeremoveBy será adicionado na próxima versão do Apache DeltaSpike 1.9.0.
A próxima seção mostra como podemos adicionar mais atributos às consultas.
4.3. Consulta com muitas propriedades
Na consulta, podemos usarmany properties combined with and operators.
public abstract Collection findByFirstNameAndLastName(
String firstName, String lastName);
public abstract Collection findByFirstNameOrLastName(
String firstName, String lastName);
Podemos combinar quantas propriedades quisermos. A pesquisa por propriedades aninhadas também está disponível, o que mostraremos a seguir.
4.4. Consulta com propriedades aninhadas
Oquery can also use nested properties.
No exemplo a seguir, a entidadeUser tem uma propriedade de endereço do tipoAddresse a entidadeAddress tem uma propriedadecity:
@Entity
public class Address {
private String city;
// ...
}
@Entity
public class User {
@OneToOne
private Address address;
// ...
}
public abstract Collection findByAddress_city(String city);
4.5. Pedido na consulta
DeltaSpike nos permitedefine an order in which result should be returned. Podemos definir ambos - ordem crescente e decrescente:
public abstract List findAllOrderByFirstNameAsc();
Como mostrado acima, tudowe have to do is to add a part to the method name which contains property name we want to sort by and the short name for the order direction.
Podemos combinar muitos pedidos facilmente:
public abstract List findAllOrderByFirstNameAscLastNameDesc();
A seguir, mostraremos como limitar o tamanho do resultado da consulta.
4.6. Limitar tamanho e paginação do resultado da consulta
Existem casos de uso em que queremos recuperar algumas primeiras linhas de todo o resultado. É o chamado limite de consulta. Também é simples com o módulo de dados:
public abstract Collection findTop2OrderByFirstNameAsc();
public abstract Collection findFirst2OrderByFirstNameAsc();
First etop podem ser usados alternadamente.
Podemos entãoenable query pagination by providing two additional parameters: @FirstResult and @MaxResult:
public abstract Collection findAllOrderByFirstNameAsc(@FirstResult int start, @MaxResults int size);
Já definimos muitos métodos no repositório. Alguns deles são genéricos e devem ser definidos uma vez e usados por cada repositório.
O Apache DeltaSpike fornece alguns tipos básicos que podemos usar para ter muitos métodos prontos para uso.
Na próxima seção, vamos nos concentrar em como fazer isso.
5. Tipos básicos de repositório
Paraget some basic repository methods, our repository should extend basic type provided by Apache DeltaSpike. Existem alguns deles comoEntityRepository,FullEntityRepository, etc .:
@Repository
public interface UserRepository
extends FullEntityRepository {
// ...
}
Ou usando uma classe abstrata:
@Repository
public abstract class UserRepository extends AbstractEntityRepository {
// ...
}
A implementação acima nos fornece muitos métodos sem escrever linhas de código adicionais, por isso ganhamos o que queríamos - reduzimos o código do clichê em massa.
Caso estejamos usando o tipo de repositório básico, não há necessidade de passar um valor de atributoforEntity adicional para nossa anotação@Repository.
Quando estamos usando classes abstratas em vez de interfaces para nossos repositórios, temos uma possibilidade adicional de criar uma consulta personalizada.
Abstract base repository classes, e.g., AbstractEntityRepository gives us an access to fields (via getters) or utility methods which we can use to create a query:
public List findByFirstName(String firstName) {
return typedQuery("select u from User u where u.firstName = ?1")
.setParameter(1, firstName)
.getResultList();
}
No exemplo acima, usamos um método utilitáriotypedQuery para criar uma implementação customizada.
A última possibilidade de criar uma consulta é usar a anotação@Query que mostraremos a seguir.
6. @Query Anotação
O SQLquery to execute can also be defined with the @Query annotation. É muito semelhante à solução Spring. Temos que adicionar uma anotação ao método com a consulta SQL como um valor.
Por padrão, esta é uma consulta JPQL:
@Query("select u from User u where u.firstName = ?1")
public abstract Collection findUsersWithFirstName(String firstName);
Como no exemplo acima, podemos facilmente passar parâmetros para a consulta por meio de um índice.
No caso de desejarmos passar a consulta por SQL nativo em vez de JPQL, precisamos definir o atributo de consulta adicional -isNative com valor verdadeiro:
@Query(value = "select * from User where firstName = ?1", isNative = true)
public abstract Collection findUsersWithFirstNameNative(String firstName);
7. Conclusão
Neste artigo, abordamos a definição básica do Apache DeltaSpike e focamos na parte interessante - módulo Dados. É muito semelhante ao Projeto Spring Data.
Exploramos como implementar o padrão de repositório. Também introduzimos três possibilidades de como definir uma consulta para executar.
Como sempre, os exemplos de código completos usados neste artigo estão disponíveisover on Github.