[Resolvido] Hibernate retornando dados duplicados em consulta

1 resposta
T

Olá todos.

Tenho um banco de dados com 3 tabelas: Contact, Contact_phone e Contact_has_Contact_phone, representando uma agenda telefônica simples. São mapeadas pelas classes Contact e ContactPhone. O problema é que, quando faço uma consulta por todos os contatos no banco, a lista retornada pelo Hibernate possui contatos aparecendo mais de uma vez, sendo que é sempre correspondente à quantidade de nºs de telefone que ele possui.

Exemplo:

Crio um contato com nome "Teste A" e com os telefones 123, 456, 789 e 000. Este contato é salvo no banco de dados e é gerado um código 1500 para ele. Até aí, o banco de dados só possui 1 registro em Contact, 4 em Contact_phone e 4 em Contact_has_Contact_phone. Porém, quando é feita uma consulta por todos os registros (um SELECT * FROM Contact), é retornada uma lista possuindo o contato "Teste A" quatro vezes, cada um com todos os seus 4 números de telefone.

Qual poderia ser o problema?

Abaixo o código de tudo que é feito antes e durante a consulta:

MainJFrame.java
/**
     * Atualiza a tabela de contatos. Método executado sempre que a janela é aberta ou o botão ATUALIZAR é clicado.
     */
    private void updateTable()
    {
        // adiciona todos os contatos da base de dados ao modelo da tabela
        ((ContactTableModel) this.contactsTable.getModel())
                .setContacts(this.contactRepository.findAll());
    }
Repository.java
// já dei um System.out.println na lista retornada por este método e o erro realmente vem daqui
    public List<T> findAll() throws RepositoryException
    {
        try
        {
            getSession().beginTransaction();
            List<T> result = this.session.createCriteria(getStoreClass()).list();
            getSession().getTransaction().commit();
            return result;
        }
        catch (Exception exception)
        {
            getSession().getTransaction().rollback();
            throw new RepositoryException(exception);
        }
        finally
        {
            getSession().close();
        }
    }

O mapeamento da relação entre as duas entidades:

Contact.java
public class Contact implements Cloneable, Serializable
{
    ...

    /** Todos os números de telefone do contato. */
    @ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(name="Contact_has_Contact_phone", schema="public",
        joinColumns={@JoinColumn(name="Contact_Cd_Contact")},
        inverseJoinColumns={@JoinColumn(name="Contact_phone_Cd_Contact_phone")})
    private List<ContactPhone> contactPhones;
}
ContactPhone.java
public class ContactPhone implements Cloneable, Serializable
{
    ...

    /** Os contatos que possuem este número de telefone. */
    @ManyToMany(fetch=FetchType.LAZY,
        cascade={CascadeType.MERGE, CascadeType.PERSIST},
        mappedBy="contactPhones")
    private Collection<Contact> contacts;
}

SQL gerado durante a consulta:

Hibernate: 
    /* criteria query */ select
        this_.Cd_contact as Cd1_0_1_,
        this_.Ds_address as Ds2_0_1_,
        this_.Dt_birthday as Dt3_0_1_,
        this_.Ds_email as Ds4_0_1_,
        this_.Nm_first_name as Nm5_0_1_,
        this_.Nm_surname as Nm6_0_1_,
        contactpho2_.Contact_Cd_Contact as Contact1_3_,
        contactpho3_.Cd_contact_phone as Contact2_3_,
        contactpho3_.Cd_contact_phone as Cd1_1_0_,
        contactpho3_.Ds_phone as Ds2_1_0_,
        contactpho3_.Nr_phone as Nr3_1_0_ 
    from
        public.Contact this_ 
    left outer join
        public.Contact_has_Contact_phone contactpho2_ 
            on this_.Cd_contact=contactpho2_.Contact_Cd_Contact 
    left outer join
        public.Contact_Phone contactpho3_ 
            on contactpho2_.Contact_phone_Cd_Contact_phone=contactpho3_.Cd_contact_phone

1 Resposta

T

Resolvido, o método findAll agora está assim:

public List<T> findAll() throws RepositoryException
    {
        try
        {
            getSession().beginTransaction();

            Criteria criteria = this.session.createCriteria(getStoreClass());
            criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
            List<T> result = criteria.list();

            getSession().getTransaction().commit();
            
            return result;
        }
        catch (Exception exception)
        {
            getSession().getTransaction().rollback();
            throw new RepositoryException(exception);
        }
        finally
        {
            getSession().close();
        }
    }

Bastou adicionar setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) à Criteria.

Criado 4 de junho de 2010
Ultima resposta 6 de jun. de 2010
Respostas 1
Participantes 1