Hibernate Fetch Select ou Join - hbm p/ annotations

7 respostas
romuloff

Na minha aplicação quero que um objeto aninhado se “auto-popule” (baseado em seu ID/PK) quando eu salvar o objeto que aninha ele.
No caso da minha aplicação é assim:
meu Imposto tem um Estado. na hora de salvar Imposto só quero fazer ± assim:
"impostoTO.setEstadoTO(new Estado(12L));"
e assim que eu buscar esse imposto recem-salvo já virá com TODOS os atributos do Estado com id 12.

Quando eu utilizava hbm em outros projetos; o relativo que funcionava era assim:
ImpostoTO.hbm.xml: <many-to-one name="estadoTO" class="br.com.ctbc.avalia.model.data.EstadoTO" fetch="select" lazy="false"> <column name="ESTADO_ID" /> </many-to-one>

Mas no meu projeto atual estou utilizando annotations e tentei fazer assim:
ImpostoTO.java:import javax.persistence.ManyToOne; import javax.persistence.JoinColumn; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; . . . @ManyToOne( targetEntity = EstadoTO.class ) @JoinColumn( name = "ESTADO_ID", nullable = false ) @Fetch( FetchMode.SELECT ) public EstadoTO getEstadoTO() { return estadoTO; }

E não deu certo.
Não é um erro; mas continua vindo somente o id de EstadoTO nos ImpostoTO’s recem-salvos.
O mais estranho é que se eu reinicio o servidor aí vem tudo populado (como eu quero desde a hora que salva).

7 Respostas

romuloff
Tentei usar o flush no DAO do Imposto já que quando eu reinicio o servidor o resultado fica do jeito que quero (trazendo TODOS atributos de Estado). [color=red]Mas tambem não deu certo.[/color]
/* (non-Javadoc)
     * @see br.com.ctbc.avalia.persistence.dao.IImpostoDAO#create()
     */
    @Override
    public Long create( ImpostoTO impostoTO ) throws PersistenceException {
        try {
            super.beginTransaction();
            Long id = super.create( impostoTO );
            super.commitTransaction();
            getSession().flush();
            return id;
        } catch ( Exception e ) {
            super.rollbackTransaction();
            throw new PersistenceException( e );
        }
    }
A solução que não quero pra solucionar o problema real é ter q fazer o find toda vez q for salvar um objeto que tenha objetos aninhados:
public Long create( ImpostoTO impostoTO ) throws InvalidParameterException,
            AlreadyExistsException {
        
        //...

        // 'populando' objetos aninhados em imposto
        impostoTO.setEstadoTO( estadoDAO.findById( impostoTO
                .getEstadoTO().getEstadoId() ) );

        return impostoDAO.create( impostoTO );
    }
[color=red](THIS IS BORING)[/color]
romuloff

alguem sabe o que falta ? um chute pelo menos ? nada ?

Gerson_da_S_Lima

@Fetch(FetchMode.JOIN)

acho que isso resolve

romuloff

Gerson da S. Lima:
@Fetch(FetchMode.JOIN)

acho que isso resolve


Tambem não funcionou com o JOIN
Já havia tentado e esqueci de comentar.

Ainda não é a solução ideal e nem a que eu estou procurando; [color=blue]//ALGUEM POR FAVOR ME DIZ O QUE FALTA PRO FETCH SELECT OU FETCH JOIN FUNCIONAR[/color]
mas achei uma um pouco menos feia do que a descrita anteriormente por mim:

ImpostoTO.java: //@LazyToOne( LazyToOneOption.FALSE ) //@Fetch( FetchMode.SELECT ) //@Fetch( FetchMode.JOIN ) @ManyToOne @Cascade( CascadeType.REFRESH ) @JoinColumn( name = "ESTADO_ID", nullable = false ) public EstadoTO getEstadoTO() { return estadoTO; }ultima linha antes do retorno de ImpostoService.java/create()://refresh to load related entities refresh( impostoTO );

Gerson_da_S_Lima

já esperimentou fazer isso:

@ManyToOne(fetch = FetchType.EAGER)

é equivalente no seu hbm.xml a lazy=“false”

só que o problema aqui é a performance, não sei se você já viu a diferença do lazy=“true” e lazy=“false”, se não posta aí que eu tento te explicar.

o melhor seria deixar o lazy=“true” e o trecho que eu descrevi acima como: @ManyToOne(fetch = FetchType.LAZY) e você carregar os relacionamentos que precisar.

romuloff

Gerson da S. Lima:
já esperimentou fazer isso:

@ManyToOne(fetch = FetchType.EAGER)
é equivalente no seu hbm.xml a lazy=“false”

só que o problema aqui é a performance, não sei se você já viu a diferença do lazy=“true” e lazy=“false”, se não posta aí que eu tento te explicar.
o melhor seria deixar o lazy=“true” e o trecho que eu descrevi acima como: @ManyToOne(fetch = FetchType.LAZY) e você carregar os relacionamentos que precisar.


Tambem não funcionou. Tentei o EAGER com o @Fetch( FetchMode.SELECT ) e com o FetchMode.JOIN
No caso do ManyToOne o lazy false não implica tanto em performance. Acontece mais no OneToMany ou quando o objeto aninhado (EstadoTO) é muito 'abrangente… que não é o caso.

Acabei de tentar colocando estas propriedades no hibernate.cfg.xml (tambem nao resolveu):

3
16
8

romuloff

Como ainda não resolveu pelo Fetch, mantive a solução do refresh. Mas fiz a alteração tirando o refresh do ImpostoService.java e passei pro DAO generico.
Engraçado que esse refresh funcionou do jeito que estava funcionando mesmo eu removendo o @Cascade( CascadeType.REFRESH ) do getEstadoTO ...

De qualquer forma ainda fica minha dúvida de como fazer isto funcionar com o Fetch.

I:
Ainda não é a solução ideal e nem a que eu estou procurando; [color=blue]//ALGUEM POR FAVOR ME DIZ O QUE FALTA PRO FETCH SELECT OU FETCH JOIN FUNCIONAR[/color]

Enfim, a solução provisória ficou assim: AbstractHibernateDAO.create-ultima linha:
//refresh to load related entities
refresh( obj );
ImpostoTO.java:
@ManyToOne( fetch = FetchType.EAGER )
    @Fetch( FetchMode.JOIN ) // NAO ESTA FUNCIONANDO. (utilizando refresh no AbstractHibernateDAO.create)
    @LazyToOne( LazyToOneOption.FALSE )
    @JoinColumn( name = "ESTADO_ID", nullable = false )
    public EstadoTO getEstadoTO() {

        return estadoTO;
    }
Criado 17 de junho de 2009
Ultima resposta 7 de ago. de 2009
Respostas 7
Participantes 2