Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

JSF com múltiplas consultas ao banco provavelmente desnecessárias

Bom dia,

ao acessar a página livro.xhtml eu notei que várias consultas repetidas são feitas ao banco:

Hibernate: select autor0_.id as id1_, autor0_.nome as nome1_ from Autor autor0_
Hibernate: select livro0_.id as id0_, livro0_.dataLancamento as dataLanc2_0_, livro0_.isbn as isbn0_, livro0_.preco as preco0_, livro0_.titulo as titulo0_ from Livro livro0_
Hibernate: select livro0_.id as id0_, livro0_.dataLancamento as dataLanc2_0_, livro0_.isbn as isbn0_, livro0_.preco as preco0_, livro0_.titulo as titulo0_ from Livro livro0_
Hibernate: select livro0_.id as id0_, livro0_.dataLancamento as dataLanc2_0_, livro0_.isbn as isbn0_, livro0_.preco as preco0_, livro0_.titulo as titulo0_ from Livro livro0_

Por que isso ocorre? Não deveria ser feita uma única consulta à tabela Livro?

livro.xhtml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

<h:head/>

<h:body>
    <h1>Novo Livro</h1>
    <h:form>
        <h:messages id="messages" />    
        <fieldset>
            <legend>Dados do Livro</legend>
            <h:panelGrid columns="2">

                <h:outputLabel value="Titulo:" for="titulo" />
                <h:inputText id="titulo" value="#{livroBean.livro.titulo}" required="true" 
                            requiredMessage="Título Obrigatório" validatorMessage="Título não pode ser superior a 40">
                    <f:validateLength maximum="40" />
                    <f:ajax event="blur" render="messages" />
                </h:inputText>

                <h:outputLabel value="ISBN:" for="isbn" />
                <h:inputText id="isbn" value="#{livroBean.livro.isbn}" validator="#{livroBean.comecaComDigitoUm}">
                    <f:ajax event="keypress" render="messages" />
                </h:inputText>

                <h:outputLabel value="Preço:" for="preco" />
                <h:inputText id="preco" value="#{livroBean.livro.preco}" validatorMessage="Valor deve ser entre 1 e 1000." >
                    <f:validateDoubleRange minimum="1.00" maximum="1000.00" />
                </h:inputText>

                <h:outputLabel value="Data de Lançamento:" for="dataLancamento" />
                <h:inputText id="dataLancamento" value="#{livroBean.livro.dataLancamento.time}">
                    <f:convertDateTime pattern="dd/MM/yyyy HH:mm"  />
                </h:inputText>

            </h:panelGrid>
        </fieldset>

        <h:commandButton value="Gravar" action="#{livroBean.gravar}">
            <f:ajax execute="@form" render="@form :tabelaLivros" />
        </h:commandButton>

        <fieldset>
            <legend>Dados do Autor</legend>
            <h:outputLabel value="Selecione Autor:" for="autor" />
            <h:selectOneMenu id="autor" value="#{livroBean.autorId}">
                <f:selectItems value="#{livroBean.autores}" var="autor" itemLabel="#{autor.nome}" itemValue="#{autor.id}" />
            </h:selectOneMenu>

            <h:commandButton value="Gravar Autor" action="#{livroBean.gravarAutor}">
                <f:ajax execute="autor" render="listaDeAutores" />
            </h:commandButton>

            <br />

            <h:commandLink value="Cadastrar novo autor" action="#{livroBean.formAutor}" immediate="true" />

            <h:dataTable value="#{livroBean.autoresDoLivro}" var="autor" id="listaDeAutores">
                <h:column>
                    <h:outputText value="#{autor.nome}" />
                </h:column>
            </h:dataTable>
        </fieldset>
    </h:form>

    <h:dataTable id="tabelaLivros" value="#{livroBean.livros}" var="livro">
        <h:column>
            <f:facet name="header">Título</f:facet>
            <h:outputText value="#{livro.titulo}" />
        </h:column>

        <h:column>
            <f:facet name="header">ISBN</f:facet>
            <h:outputText value="#{livro.isbn}" />
        </h:column>

        <h:column>
            <f:facet name="header">Preço</f:facet>
            <h:outputText value="#{livro.preco}" />
        </h:column>

        <h:column>
            <f:facet name="header">Data</f:facet>
            <h:outputText value="#{livro.dataLancamento.time}">
                <f:convertDateTime pattern="dd/MM/yyyy HH:mm"  />
            </h:outputText>
        </h:column>
    </h:dataTable>

</h:body>

</html>

LivroBean.java

package br.com.caelum.livraria.bean;

import java.io.Serializable;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;

import br.com.caelum.livraria.dao.DAO;
import br.com.caelum.livraria.modelo.Livro;
import br.com.caelum.livraria.modelo.Autor;

@ManagedBean
@ViewScoped
public class LivroBean implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 6891623185316861600L;

    private Livro livro = new Livro();
    private Integer autorId;

    public void setAutorId(Integer autorId) {
        this.autorId = autorId;
    }

    public Integer getAutorId() {
        return autorId;
    }

    public Livro getLivro() {
        return livro;
    }

    public List<Autor> getAutores (){
        return new DAO<Autor>(Autor.class).listaTodos();
    }

    public List<Autor> getAutoresDoLivro(){
        return this.livro.getAutores();
    }

    public List<Livro> getLivros() {
        return new DAO<Livro>(Livro.class).listaTodos();
    }

    public void gravarAutor(){
        Autor autor = new DAO<Autor>(Autor.class).buscaPorId(this.autorId);
        this.livro.adicionaAutor(autor);        
    }

    public String formAutor(){
        System.out.println("Chamando o formulário do Autor");
        return "autor?faces-redirect=true";
    }

    public void comecaComDigitoUm(FacesContext fc, UIComponent component, Object value) throws ValidatorException {
        String valor = value.toString();

        if(!valor.startsWith("1")){
            throw new ValidatorException(new FacesMessage("Deveria começar com 1"));
        }
    }

    public void gravar() {
        System.out.println("Gravando livro " + this.livro.getTitulo());

        if (livro.getAutores().isEmpty()) {
            FacesContext.getCurrentInstance().addMessage("autor", new FacesMessage("Livro deve ter pelo menos um Autor."));
        }

        new DAO<Livro>(Livro.class).adiciona(this.livro);

        this.livro = new Livro();
    }

}
1 resposta
solução!
 public List<Autor> getAutores (){
        return new DAO<Autor>(Autor.class).listaTodos();
    }

    public List<Autor> getAutoresDoLivro(){
        return this.livro.getAutores();
    }

    public List<Livro> getLivros() {
        return new DAO<Livro>(Livro.class).listaTodos();
   }

O tempo você vai no banco nos getters... como você não tem controle em relação ao número de vezes que esses métodos vão ser chamados, acaba dando ruim para você. Nos getters do seu managed bean você deve sempre programar para fazer no máximo uma consulta e depois guardar o resultado no managed bean, em um atributo.