Fazer um consulta na base de dados, retornar alguns registros e criar uma tela para pesquisa contendo ordenação e paginação é uma tarefa repetitiva no desenvolvimento de aplicações.
Pensando nisso, o framework JBoss Seam fornece uma classe chamada EntityQuery que, ao ser herdada, fornece todos os métodos necessários para execução e retorno da consulta, ordenação e paginação dos registros. Por exemplo, suponha uma classe persistente chamada EntidadeA, o código abaixo já é mais do que o suficiente para construção de uma tela de exibição e pesquisa:
@Name(“entidadeAList”)
public class EntidadeAList extends EntityQuery<EntidadeA> {
private static final String EJBQL = “select a from EntidadeA a”
private static final String[] RESTRICTIONS = { “lower(a.campoA) like lower(concat(#{entidadeAList.entidade.campoA},’%'))”,}
public EntidadeAList() {
setEjbql(EJBQL);
setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
setMaxResults(10);
}
private EntidadeA entidade A;
//Get e Set para entidadeA
}
Prontinho!!! É só criar sua página de exibição e chamar os métodos disponíveis na classe.
Infelizmente (ou felizmente!?), nem todas as aplicações são tão simples asssim. Desenvolvimento uma dessas aplicações não tão simples, precisei de um DTO para encapsular joins espaciais e outras operações geométricas sobre as entidades persistentes. Segue abaixo o pseudo-código:
@Name(“entidadeDTOList”)
public class EntidadeDTOList extends EntityQuery<EntidadeDTO> {
private static final String EJBQL = “select new meupacote.EntidadeDTO(a.nome, intersection(a.theGeom, b.theGeom)) from EntidadeA a, EntidadeB b”
private static final String[] RESTRICTIONS = {“intersects(a.theGeom, b.theGeom) = #{true}”, “lower(a.campoA) like lower(concat(#{entidadeDTOList.entidade.campoA},’%'))”,}
public EntidadeAList() {
setEjbql(EJBQL);
setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
setMaxResults(10);
}
private EntidadeA entidade A;
//Get e Set para entidadeA
}
Nesse caso, simplesmente herdar de EntityQuery não funcionou. O método de navegação “lastFirstResult” dispara a exceção “invalid select clause for query”.
Investigando mais de perto, abri o código-fonte da super classe Query e observei que o erro estava acontecendo dentro do método getCountEjbql(). O grande problema é que a seguinte expressão regular usada pelo Seam não abrange casos um pouco mais complexos:
SUBJECT_PATTERN = “Pattern.compile(“^select(\\w+((\\s+|\\.)\\w+)*\\s+from”, Pattern.CASE_INSENTIVE)
Como não queria criar um fork do Seam “corrigindo” o pattern, preferi sobrescrever o método na minha classe, que no final ficou parecida com o código abaixo:
@Name(“entidadeDTOList”)
public class EntidadeDTOList extends EntityQuery<EntidadeDTO> {
private static final String EJBQL = “select %s from EntidadeA a, EntidadeB b where intersects(a.theGeom, b.theGeom) = true”
private static final String EJBQL_PROJ = “new meupacote.EntidadeDTO(a.nome, intersection(a.theGeom, b.theGeom))”
private static final String[] RESTRICTIONS = { “lower(a.campoA) like lower(concat(#{entidadeDTOList.entidade.campoA},’%'))”,}
public EntidadeAList() {
setEjbql(String.format(EJBQL, EJBQL_PROJ);
setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
setMaxResults(10);
}
@Override
protected String getCountEjbql() {
String query = getRenderedEjbql();
query = query.replace(EJBQL_PROJ, “count(c)”);
return query;
}
private EntidadeA entidade A;
//Get e Set para entidadeA
}
Agora sim! Funcionando de forma satisfatória, porém não ideal. Acho que o Seam já poderia ter feito uma expressão regular que contemplasse esses casos.
Até a próxima!





