JSF repete buscas

Gostaria de saber porque quando faço uma busca simples no BD usando JSF ele repete pelo menos 3 vezes a mesma consulta antes de ir para o jsp que mostra o resultado.

Obrigado

Opa,

Bem geralmente ele repete o método get 2 vezes, uma antes do processamento de sua action e outra depois, seguindo o ciclo de vida do Faces. Bem sugiro que crie um atributo de instância e em um backing bean de escopo request e no método get faça a pesquisa no banco apenas se o objeto estiver nulo.

:okok:

Isso acontece porque o nome do método começa com get ou nada a ver? Pelo menos para cadastrar, editar e excluir ele passa somente uma vez pelo método e não começa com get.
Isso que sugeriu seria como um flag no inicio do método por exemplo com um valor true, e depois de ele executa uma condição se o flag for true executa o sql e depois muda o flag para false ou não?

Obrigado

Na verdade o problema é que quando você associa a um atributo na sua view que acontece isso, porque ele executa nas duas fases como disse no post anterior. E a função é executada apenas na fase de execução.

:okok:

OK, entendi o que está acontecendo, mas não entendi como resolver isso:

Poderia dar um exemplo para esclarecer melhor?

Obrigado

Uma coisa que percebi é que se eu tiver 30 itens sendo listados na tela pelo dataTable ele repete 30 vezes o método chamado pelo commandLink, isso acaba com a performance de qualquer BD, alguém saberia como posso resolver isso?

Opa,

faça o que eu já lhe falei, crie uma variavel global e faça a seleção apenas uma vez. Aí no seu método que retorna a lista, você faz os testes se a variável já tiver sido preenchida, ele apenas retorna ela, senão ele lista no banco e salva nesta variável.

Quanto o que você falou não tem muita idéia não, pode ser que você fez alguma coisa errada.

:okok:

Eu já tinha feito isso, mas quando é atualizado algum item e clico para ver os detalhes não busca novamente no BD porque a variavel global não está nula, isso resolve o problema de não repetir as buscar, mas não atualiza. Nem mesmo clicando em outro link, tenho que sair e entrar novamente para poder atualizar.

ah bom, matenha isto na e quando você atualizar alguma informação lembre-se de limparar estes dados.

:okok:

Não sei mais o que fazer… tentei de tudo, da uma olhada no meu código se estou fazendo alguma coisa errada, esta é a classe:

    public String buscar() throws AlmoxarifadoExceptions {
        String result = "FALHA";
        try {
            //para pegar valor do commandLink
            FacesContext context = FacesContext.getCurrentInstance();
            Map map = context.getExternalContext().getRequestParameterMap();
            tipoID = Integer.parseInt((String) map.get("tipoID"));
            tipoDAO.buscar(tipoID);
            result = "SUCESSO";
        } catch (SQLException sqlBuscarTipo) {
            result = "FALHA";
            throw new AlmoxarifadoExceptions(sqlBuscarTipo.getClass().getName(),
                "buscarTipo", sqlBuscarTipo.getMessage());            
        }
        return result;
    }

O método buscar é esse:

    public void buscar(int tipoID) throws AlmoxarifadoExceptions, SQLException {
        try {
            bd.open();
            bd.psmt = bd.conn.prepareStatement("SELECT * FROM Tipos " +
                "WHERE TipoID = ?");
            bd.psmt.setInt(1, tipoID);
            bd.rs = bd.psmt.executeQuery();
            if (bd.rs.next()) {
                preencheTipos(tipoDTO);
            }
        } finally {
            bd.closeAll();
        }
    }

O preencheTipos vai setar os beans só, na página esta assim:

<t:dataTable 
   id="listar"
   value="#{tipoSession.listar}"
   var="dados"
   rows="25">
   <h:column>
      <f:facet name="header">
         <h:outputText value="#{msgs.tiposTipo}" styleClass="textoColunas"/>
      </f:facet>
      <h:outputText value="#{dados.tipo}" styleClass="texto"/>
   </h:column>
   <h:column>
      <f:facet name="header">
         <h:outputText value="#{msgs.tiposInsumo}" styleClass="textoColunas"/>
      </f:facet>
   <h:outputText value="#{dados.insumo}" styleClass="texto"/>
   </h:column>                            
   <h:column>
      <f:facet name="header">
         <h:outputText value="#{msgs.tiposDetalhes}" styleClass="textoColunas"/>
      </f:facet>
      <h:commandLink value="#{msgs.detalhes}" styleClass="texto" action="#{tipoSession.buscar}">
         <f:param name="tipoID" value="#{dados.tipoID}"/>
      </h:commandLink>
   </h:column>
</t:dataTable>

Já tentei usando uma variavel global que muda de valor quando é realizado a busca apenas uma vez, já tentei limpar os dados depois de realizar a busca uma vez, o problema é que se tiver 25 dados na tela ele executa 25 vezes a mesma consulta.

Obrigado pela ajuda!

coloque para mim seu método listar… porque desta forma que você colocou não dá para saber…

:okok:

O método listar é este:

    public Result getListar() throws AlmoxarifadoExceptions, SQLException {
        try {
            bd.open();
            bd.psmt = bd.conn.prepareStatement("SELECT * FROM Tipos ORDER BY Tipo");
            bd.rs = bd.psmt.executeQuery();
            return ResultSupport.toResult(bd.rs);
        } finally {
            bd.closeAll();
        }
    }

O método buscar é quando clico no link para pegar o registro pelo ID, esse método buscar repete dependento do número de registros na tela, se tiver 25 registros repete 25 vezes o método, fazendo 25 vezes a mesma consulta, tem alguma coisa muito errada nisso… mas não tá fácil encontrar

Obrigado novamente

Tentei usar um binding UIData e um HtmlDataTable para pegar o valor selecionado no dataTable, tentei também

  FacesContext ctx       = FacesContext.getCurrentInstance();
  ValueBinding binding   = ctx.getApplication().createValueBinding("#{dados}");

Ambos funcionam mas ambos repetem o mesmo método conforme o número de dados mostrados na tela. Já não sei mais o que fazer…

[quote=“fpmx”]O método listar é este:

    public Result getListar() throws AlmoxarifadoExceptions, SQLException {
        try {
            bd.open();
            bd.psmt = bd.conn.prepareStatement("SELECT * FROM Tipos ORDER BY Tipo");
            bd.rs = bd.psmt.executeQuery();
            return ResultSupport.toResult(bd.rs);
        } finally {
            bd.closeAll();
        }
    }

O método buscar é quando clico no link para pegar o registro pelo ID, esse método buscar repete dependento do número de registros na tela, se tiver 25 registros repete 25 vezes o método, fazendo 25 vezes a mesma consulta, tem alguma coisa muito errada nisso… mas não tá fácil encontrar

Obrigado novamente[/quote]
tenta armazenar o resultado e só consultar se a variavel for nula, algo como:

private Result lista;
    public Result getListar() throws AlmoxarifadoExceptions, SQLException {
if (lista!=null)
return lista;
        try {
            bd.open();
            bd.psmt = bd.conn.prepareStatement("SELECT * FROM Tipos ORDER BY Tipo");
            bd.rs = bd.psmt.executeQuery();
lista = ResultSupport.toResult(bd.rs);
            return lista;
        } finally {
            bd.closeAll();
        }
    }

[quote=“fpmx”]Tentei usar um binding UIData e um HtmlDataTable para pegar o valor selecionado no dataTable, tentei também

  FacesContext ctx       = FacesContext.getCurrentInstance();
  ValueBinding binding   = ctx.getApplication().createValueBinding("#{dados}");

Ambos funcionam mas ambos repetem o mesmo método conforme o número de dados mostrados na tela. Já não sei mais o que fazer…[/quote]
a forma mais fácil de saber a linha selecionada em um datatable é usando um table listener para o datamodel.

seta os dados da tabela para um ListDataModel (que pode ser criado a partir de uma List)
e adiciona um DataModelListener neste cara e pronto :smiley:

ou então coloca um t:updateActionListener na tua tabela (componente do tomahawk)

ou se estiver usando o spring-annotation:
@DataModel e @DataModelSelection ja resolvem …

Isso de armazenar o resultado é o que estou usando por enquanto, mas tem um problema, se outra pessoa atualizar algum dado de um registro para mim aparece desatualizado porque a variavel não está vazia.

Usando o t:updateActionListener para pegar o ID não está funcionando ele repete o método chamado pelo commandLink conforme o número de registros mostrados pelo dataTable e mostra na tela de edição somente o último registro.

Estou pesquisando sobre o ListDataModel, mas se alguém tiver um exemplo facilita…

O que eu acho estranho é que ele deveria ir para a tela de edição já na primeira passada, pois o método retorna a String para mostrar a outra tela já na primeira passada pelo método, não consigo entender porque isso não acontece.

para resolver isto muda o scope do bean para request …
um singleton não deveria ser o backing bean de uma página (pelo menos não em uma situacão normal :S )

Mudando o scope para request apresentou essa mensagem: java.lang.NullPointerException

Não tá fácil pegar esse registro do dataTable sem repetir o método, já tentei de tudo consigo pega o valor de pelo menos umas 5 formas diferentes, porém todas elas repetem o método buscar conforme quantos registros o dataTable mostra, será que o problema não está no dataTable?

Opa,

mais fácil é você passar o identificador do registro como parâmentro do seu command link… muito mais simples.

use o f:param para isto. quanto ao nullpointerexception tome cuidade que você está tentando fazer alguma referência ao seu objeto enquanto ele ainda está vazio/nulo.

:okok:

Usando o f:param como estava usando desde o começo consigo pegar o ID do item que quero alterar, mudei o scope para Request e funcionau normalmente assim como scope Session também, porém o problema de repetir o método 10 vezes se tiver 10 registros mostrados pelo dataTable ainda continua.

O erro java.lang.NullPointerException estava dando quando tentava pegar o parametro com o scope Request através do t:updateActionListener.

Usando o DataModel teoricamente o método não se repetiria, ou será que está repetindo porque meu dataTable ou o commandLink esta implementando errado? Como faço para usar esse DataModel, já testei alguns exemplos que achei no google, mas mesmo assim o método chamado pelo commandLink insiste em repetir…