Skip to content
felipe-castanon edited this page Oct 3, 2014 · 14 revisions

Table of Contents

Repository

Com o objetivo de facilitar e reutilizar código de persistência para as entidades, disponibilizou-se três tipos de suporte para rotinas de persistências:

Suporte;
Query;
Validation;

Suporte

O Suri-CDI disponibiliza os métodos da JPA em classes de suporte para facilitar a construção de repositórios. Para isso, basta que em seu projeto haja uma fábrica para o EntityManager, como por exemplo:

public class EntityManagerProducer {

	@PersistenceContext
	private EntityManager entityManager;
	
	@Produces
	public EntityManager produceEntityManager(){
		return entityManager;
	}
	
}

A lógica da criação do EntityManager fica a cargo de cada aplicação e pode ser dependente do contexto em que for injetada. Isso permite o uso de mais de um PersistenceUnit e sua correta gestão nos repositórios

As operações de manipulação de entidades utilizando JPA são encapsuladas em duas classes

EntityRepository

Essa classe serve como suporte para que o desenvolvedor possa especializar a persistência para cada entidade. É possível, por exemplo, criar uma PessoaService herdando de EntityRepository e reaproveitar vários métodos de persistência dessa entidade, dando a comodidade ao desenvolvedor de implementar apenas as operações específicas que desejar.

Dentre as diversas operações providas, podemos destacar algumas como:

/**
 * Persist (new entity) or merge the given entity. The distinction on calling either
 * method is done based on the primary key field being null or not.
 * If this results in wrong behavior for a specific case, consider using the
 * {@link org.apache.deltaspike.data.api.EntityManagerDelegate} which offers both
 * {@code persist} and {@code merge}.
 * @param entity            Entity to save.
 * @return                  Returns the modified entity.
 */
public E save(E entity);

/**
 * Convenience access to {@link javax.persistence.EntityManager#remove(Object)}.
 * @param entity            Entity to remove.
 */
public void remove(E entity);

/**
 * Convenience access to {@link javax.persistence.EntityManager#refresh(Object)}.
 * @param entity            Entity to refresh.
 */
public void refresh(E entity);

/**
 * Remove the given entity from the persistence context, causing
 * a managed entity to become detached.  Unflushed changes made
 * to the entity if any (including removal of the entity),
 * will not be synchronized to the database.  Entities which
 * previously referenced the detached entity will continue to
 * reference it.
 * @param entity  entity instance
 * @throws IllegalArgumentException if the instance is not an entity
 */
public void detach(E entity);

/**
 * Entity lookup by primary key. Convenicence method around
 * {@link javax.persistence.EntityManager#find(Class, Object)}.
 * @param primaryKey        DB primary key.
 * @return                  Entity identified by primary or null if it does not exist.
 */
public E findBy(PK primaryKey);

/**
 * Lookup all existing entities of entity class {@code <E>}.
 * @return                  List of entities, empty if none found.
 */
public List<E> findAll();

/**
 * Find entities by the given named query.
 * @param namedQuery        Named Query
 * @param params 	        Named Query parameters
 * @return                  List of entities, empty if none found.
 */
public List<E> findByNamedQuery(String namedQuery, Map<String, Object> params);

/**
 * Find single entity by the given named query.
 * @param namedQuery        Named Query
 * @param params 	        Named Query parameters
 * @return                  Entity
 */
public E findUniqueByNamedQuery(String namedQuery, Map<String, Object> params);

Para utilizar o EntityRepository como base da sua classe de persistência basta seguir o exemplo:

public class PessoaRepository extends EntityRepository<Pessoa, Long>{}

GenericEntityRepository

O GenericEntityRepository é uma classe abstrata que provê os mesmos métodos que a EntityRepository, mas com a possibilidade de ser aplicável a qualquer entidade do projeto.

Por ser abstrata, não pode ser criado um componente CDI diretamente desta classe. Para utiliza-la em um projeto basta estende-la em uma classe concreta e utiliza-la como CDI em outras classes

public class GenericEntityRepository extends br.com.surittec.suricdi.core.repository.GenericEntityRepository{}

...

@Inject
private GenericEntityRepository genericEntityRepository;

Query

A classe JPQL serve como suporte para a construção de queries utilizando a Java Persistence Query Language. Para isso, o construtor dessa classe deve receber o entityManager para que, ao final da configuração, ela possa executar a query.

A configuração da query será feita orientada a objeto e de maneira simular a uma Criteria, mas que construí uma JPQL com trechos de código para especificar o que será incluído no:

  • select;
  • from;
  • where;
  • group by;
  • order by;
  • range de resultado.

Ao final da configuração, os resultados podem ser obtidos em lista ou por um resultado único.

/**
 * Retorna uma lista de entidades que atendem aos critérios da busca.
 * Já faz o <code>cast</code> para a classe <code>resultType</code> passada.
 * 
 * @param resultType
 * @return
 */
@SuppressWarnings("unchecked")
public <T> List<T> getResultList(Class<T> resultType);

/**
 * Retorna uma lista de entidades que atendem aos critérios da busca.
 * 
 * @return
 */
public List<?> getResultList();

/**
 * Retorna uma única entidade que atenda aos critérios da busca.
 * Já faz o <code>cast</code> para a classe <code>resultType</code> passada.
 * 
 * @param resultType
 * @return
 */
@SuppressWarnings("unchecked")
public <T> T getSingleResult(Class<T> resultType);

/**
 * Retorna uma única entidade que atenda aos critérios da busca.
 * 
 * @return
 */
public Object getSingleResult();

/**
 * Retorna uma única entidade que atenda aos critérios da busca.
 * Trata o caso de não haver resultado, retornando <code>null</code>.
 * Já faz o <code>cast</code> para a classe <code>resultType</code> passada.
 * 
 * @param resultType
 * @return
 */
@SuppressWarnings("unchecked")
public <T> T getAnyResult(Class<T> resultType);

/**
 * Retorna uma única entidade que atenda aos critérios da busca.
 * Trata o caso de não haver resultado, retornando <code>null</code>.
 * 
 * @return
 */
public Object getAnyResult();

Exemplo de uso em um busca:

public List<Pessoa> findByNome(String nome){
	
	JPQL jpql = jpql().from("Pessoa");
	
	if(StringUtils.isNotBlank(nome)){
		jpql.where("nome = :nome").withParam("nome", nome);
	}
	
	return jpql.getResultList(Pessoa.class);
}
	
public boolean isUnique(Pessoa pessoa){
	
	JPQL jpql = jpql().select("count(p)").from("Pessoa p");

	jpql.where("(p.cpf = :cpf or p.email = :email)");
	jpql.withParam("cpf", pessoa.getCpf());
	jpql.withParam("email", pessoa.getEmail());
	
	if(pessoa.getId() != null){
		jpql.where("p.id != :id").withParam("id", pessoa.getId());
	}
	
	return jpql.getSingleResult(Long.class) == 0;
}

Validation

Validações são ações necessárias em qualquer sistema que trabalhe sobre um domínio específico de dados. Elas variam de acordo com os tipos de campos utilizados e podem ser específicas a certas regiões.

A API em javax.validation fornece uma série de anotações que permite que os desenvolvedores restringam o conjunto aceitável de dados em um determinado campo. Mas essas validações seguem padrões internacionais, não apresentando soluções para CPF e CNPJ, por exemplo.

O Suri-CDI possui facilidades para trabalhar com esses tipos de dados. O pacote br.com.surittec.suricdi.core.validation contem anotações para que o Java Bean Validation seja capaz de interpretar e validar um determinado campo.

A arquitetura especializa esse comportamento e disponibiliza as validações para os campos de CPF, CNPJ e E-mail da seguinte maneira:

@Cpf
@Column(name = "cpf", length = 11, unique = true, nullable = false)
private String cpf;

@Cnpj
@Column(name = "cnpj", length = 14, unique = true, nullable = false)
private String cnpj;

@Email
@Column(name = "email", length = 100, unique = true, nullable = false)
private String email;

Clone this wiki locally