PrimeFaces + Hibernate - LazyDataModel

Pessoal, eu preciso fazer uma paginação na minha dataTable do PrimeFaces…
Tenho uma consulta que traz uma pancada de registros e cada vez que troco de página utilizando o componente do PrimeFaces, ele faz toda a query novamente e fica lento demais pra trocar de página…

Percebi que se usasse o Lazy como tem no showcase do primefaces

http://www.primefaces.org/showcase/ui/datatableLazy.jsf

seria tranquilo… Até olhei o exemplo de um colega nosso aqui de fórum http://uaihebert.com/?p=1120 mas tenho um problema pra implementá-lo. Na minha consulta usando Criteria eu tenho 4 parâmetros e não sei como utilizá-los na classe LazyDataModel. Alguém poderia me dar uma luz?

Ninguém?? rs…
Só preciso colocar meus filtros que estão no Bean dentro da classe que herda LazyDataModel…

Opa e ai cara tudo bem?

Então, se você for usar os filtros do próprio Primefaces:

<p:column filterBy="" />

Você só precisa fazer uma busca no banco de dados lazy, passando o numero de dados, em qual pagina está.

Então no seu bean você vai ter que implementar aquela classe “LazyDataModel”

Vou tentar me expressar melhor.

public class UserBean {

@SuppressWarnings("serial")
	private LazyDataModel<User> createLazyData(){
		return new LazyDataModel<User>(){
			
			@Override
			public List<User> load(int first, int pageSize, String sortField,
					SortOrder sortOrder, Map<String, String> filters ) {
				List<User> result = new ArrayList<User>();		
				String filter = filters.get("Login");
                                try{
					if(filter.equals("") || filter != null){
						result = userService.searchAllDataLazy(pageSize, first, sortField,sortOrder);			
					}else{
						result = userService.searchAllDataLazyByUk(pageSize,first, sortField,sortOrder, "Login", filter)
					}
						 if (getRowCount() <= 0) {
							setRowCount(userService.countData());
						}
				}catch(Exception e){
					JSFUtil.addMessage(FacesMessage.SEVERITY_FATAL, message, true);
				}	
				setPageSize(pageSize);
				return result;
			}
		};
	}


}

Ou seja, dentro dele você verifica se o filtro do campo “Login” contem algum valor.

  • Se não, ele faz busca de todos lazy.
  • Se sim, ele faz busca com filtro lazy.

Dai você tem que implementar o DAO. Sendo que você nao precisa necessariamente do “sortOrder”/“sortField”

Seria isso?

Ops foi duas vezes sem querer

Entendi meu amigo…
É QUASE isso…
Eu não posso usar os filtros do primefaces… Mostrei pro usuário e ele preferiu da outra maneira rs…
Então eu tenho lá meus componentes <p:calendar> e <p:selectOneMenu> onde são setados esses 4 parâmetros para a pesquisa.

<p:calendar id="popupCal"  
value="#{logBean.dataInicial}">

<p:calendar id="popupCal2"  
value="#{logBean.dataFinal}">

<h:outputText value="Login: " style="width:100px"/>  
	<p:selectOneMenu value="#{logBean.login}">
		<f:selectItem itemLabel="Todos os Usuários" itemValue=""/>
		<f:selectItems value="#{usuarioBean.lista}" var="usuario"  
			itemLabel="#{usuario.login}" itemValue="#{usuario.login}"  />    			            
	</p:selectOneMenu>

// tem mais um selectOneMenu pra Tipo de Ação

Depois eu tenho um botão da seguinte maneira:

<p:commandButton id="buscarHistoricoPorFiltros" value="Filtrar" icon="ui-icon-search" action="#{logBean.buscarPorFiltros}" ajax="false" />

E abaixo eu tenho meu datatable que está configurado da seguinte maneira:

<p:dataTable id="listagemHistoricoUsuario" var="historicoUsuario" value="#{logBean.lazyLogs}" rules="groups" rowsPerPageTemplate="10,15,20,30,40,50" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" paginator="true" rows="10" lazy="true" paginatorPosition="bottom" emptyMessage="Não foram encontrados registros de histórico.">

O que eu preciso agora é enviar o valor dos parâmetros que são enviados do CommandButton pro Bean, para essa classe LazyDataModel.
Até porque pro Bean ele envia…

[code]
public class LogAplicacaoLazyList extends LazyDataModel {

private static final long serialVersionUID = 1L;
private List logs;

@Override
public List<LogAplicacao> load(int startingAt, int maxPerPage, 
		String sortField, SortOrder sortOrder, Map<String, String> filters) {
    try {
        	LogAplicaçãoDAOImpl logAplicaçãoDAOImpl = new LogAplicaçãoDAOImpl();

            //buscar valor dos parâmetros através do action do commandbutton

// logs = logAplicaçãoDAOImpl.pesquisarPorDataLoginAcao(dataInicial, dataFinal,
// login, tipoAcao, maxPerPage, startingAt);

        if(getRowCount() <= 0){
            setRowCount(logAplicaçãoDAOImpl.pesquisarQuantidadeLogComFiltro());
        }
        setPageSize(maxPerPage);
 
        return logs;
    }catch (Exception e) {
    	System.out.println("Erro ao paginar... Mensagem de erro: "+ e.getMessage());
	}
    return logs;[/code]

Em outras palavras (Resumindo pq acho que falei mto rs), o que eu preciso é filtrar minha busca mas sem os filtros do PrimeFaces…
Eu tenho tudo pronto (Query com os parâmetros certinhos)… Só preciso que a lazy loading da paginação funcione juntamente com isso rs…

Agora entendi.

Bom eu to com o mesmo problema que você xD.

Quando eu faço a busca sem ser pelos filtros do primefaces, eu simplesmente não consigo paginar. Creio que seja pq eu uso @RequestScoped.

Acho que a unica solução é você criar sua própria paginação…

Cara eu estou preso nisso há 3 dias e NADA…
Impressionante, será que ninguém nunca precisou fazer isso? rs…

Se eu não usar paginação e colocar meu Bean como @SessionScoped, (fazendo a pesquisa dentro do Bean, ao invés de fazer na classe LazyDataModel pelo método load) os registros aparecem… Mas aí é uma lentidão tremenda pra trocar de página…

Até achei um tópico daqui do guj que tem uma outra implementação interessante mas não sei se rolaria…

http://www.guj.com.br/java/275212-pdatatable-nao-mostra-resultados-enquanto-nao-clico-na-paginacao-resolvido

Se eu criar minha própria paginação vai dar um trabalho do cão e vou considerar como POG rs…

O estranho é que eu tento setar os parâmetros na mão, no código… Ele até faz a pesquisa mas não aparece NADA como resultado.

Giovani conseguiu resolver??? Eu consegui fazer o que eu queria aqui…

Então eu consigo fazer a consulta normal, tanto total quanto com filtro…

O problema é que quando eu vou paginar:

-Quando é total, funciona certinho…

-Quando é com filtro, se eu clicar para ir para a segunda pagina, ele pega como se fosse a segunda pagina da pesquisa total…

:stuck_out_tongue:

Faz o seguinte. Cria um POJO com os atributos da sua pesquisa e declara no seu ManagedBean.
E quando na view você enviar os dados da pesquisa pra algum método, coloca os dados da pesquisa numa instância desse POJO, joga no Context do Faces e dentro do seu LazyDataModel, você dá um get nesse objeto. Só não se esqueça de tratar quando o objeto vier nulo senão dá NullPointerException.

galera!!

eu estou com esse mesmo problema.
Mas a solulção que vcs estão propondo é esta:

http://www.guj.com.br/java/280014-get-object-no-load-do-lazydatamodel

onde o cara coloca o objeto no mapa da sessão?
“getSessionMap” ??

eu preciso resolver este problema.
Outra coisa é a consulta dinamica que vou precisar implementar.
Vocês podem ajudar com isto também?

PS: eu sei que o tópico é um pouco antigo, alguns meses…
mas a questão é mto relevante para mim.
Valeu!

Sim, ele coloca o objeto na sessão e depois pega de volta dentro do load.
Sobre a consulta dinâmica, o que pretende fazer?

Cara valeu pela resposta tão rápido…

Bom, consulta dinamica…vamos ao que eu tenho pronto usando os filters da datatable…

    @Override
    public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {

	List<T> data = new ArrayList<T>();
	String noneSelected = messageUtil.getMessageBundle("global.selecione");
	
	
	// Criteria
	CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
	CriteriaQuery<T> accountQuery = criteriaBuilder.createQuery(entityClass);

	// From
	Root<T> from = accountQuery.from(entityClass);

	// sort
	if (sortField != null) {
	    if (sortOrder == SortOrder.ASCENDING) {
		accountQuery.orderBy(criteriaBuilder.asc(from.get(sortField)));
	    } else {
		accountQuery.orderBy(criteriaBuilder.desc(from.get(sortField)));
	    }
	}

	// filters
	List<Predicate> predicates = new ArrayList<Predicate>();

	for (Entry<String, String> entry : filters.entrySet()) {
	    //Selecione... não é um filtro válido :)
	    if(entry.getValue().equals(noneSelected)){
		continue;
	    }
	    Expression<String> literal = criteriaBuilder.literal( "%"+entry.getValue()+"%");
	    predicates.add(criteriaBuilder.like(from.<String> get(entry.getKey()), literal));
	}
	
	accountQuery.where(predicates.toArray(new Predicate[predicates.size()]));

	// paginate
	data = entityManager.createQuery(accountQuery).setFirstResult(first).setMaxResults(getPageSize()).getResultList();

	// row count
	CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
	countQuery.select(criteriaBuilder.count(countQuery.from(entityClass)));
	countQuery.where(predicates.toArray(new Predicate[predicates.size()]));
	int rowCount = entityManager.createQuery(countQuery).getSingleResult().intValue();
	setRowCount(rowCount);

	return data;
    }

Proximo passo é usar o MAP que vou colocar na sessão com os filtros…
Depois eu tenho que arrumar para funcionar com os JOINs né…

Imagine:

Classe Pessoa:

  • Nome
  • Idade
  • Data nascimento

Esta classe tem relacionamento com:

Classe Cargo

  • Descricao

e

Classe Animal

  • Apelido
  • Raça

aí quero fazer um form que o cara pesquisa por:
Pessoa.Nome
Pessoa.Idade
Pessoa.DataNascimento
Cargo.descricao
Animal.apelido
Animal.raca

A consulta seria algo como:

Pessoa.Nome = valor OR Pessoa.Idade = valor OR Pessoa.DataNascimento = valor
AND
(Faz o join) Cargo.descricao = valor
AND
(Faz o join) Animal.apelido = valor OR Animal.raca = valor

Algo mais ou menos assim, só que dynamico… e genérico.
O que acha sobre isso? Tem sugestões?

Só pra eu ter certeza…
Você não quer utilizar mesmo os filtros do PrimeFaces né?
Porque existe um campo dinâmico e genérico onde você poderia colocar pro usuário digitar todos esses atributos de pesquisa.

Caso não, eu faria de uma maneira que não considero bonita.

Colocaria esses parâmetros de pesquisa dentro de uma POJO, setaria sempre no load do LazyDataModel e lá dentro quando fosse chamar o DAO, faria a verificação de qual campo ele digitou (de acordo com o parâmetro que fosse setado) e chamaria a DAO correspondente.

Mas creio que deva existir um modo mais bonito de fazer isso.

humm…

como vc faz para que o evento (action ou actionListener) do botão de pesquise
faça com que o método LOAD do primefaces seja executado?

Basicamente tenho uma dataTable que tem como VALUE uma lista de LazyModel.

<p:dataTable id="listagemAlunos" var="aluno" value="#{alunoBean.lazyModel}">

No get desse LazyModel é que a função load se encontra. Então toda vez que eu mexo na lista (por exemplo um simples refresh na página), ele aciona o método load.

Então a cada vez que eu digito um parâmetro diferente na minha página e ela jogar pro método, basta que eu coloque o endereço no return do método…

Exemplo:

return "/publico/listaAlunos";

Ou você pode programar via Ajax também. :slight_smile: