Consulta com a API Criteria retorna valores de associação repetidos

0 respostas
H

E aí pessoal… boa tarde.

No desenvolvimento de um sistema, onde uso hibernate, spring e jsf, precisei mapear as duas entidades a seguir.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "documento")
public class Documento implements Serializable {

    private static final long serialVersionUID = 1l;
    private Integer id;
    private Set<Movimento> movimentos = new LinkedHashSet<Movimento>();

    ...

    /**
     * @return the movimentos
     */
    @OneToMany(mappedBy = "documento", fetch = FetchType.EAGER)
    @OrderBy("envio")
    public Set<Movimento> getMovimentos() {
        return movimentos;
    }
}
@Entity
@Table(name = "movimento")
public class Movimento implements Serializable {

    private static final long serialVersionUID = 1l;
    private MovimentoPK movimentoPK;
    private Documento documento;

    ...

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "cd_documento", referencedColumnName = "cd_documento", insertable = false, updatable = false)
    @Cascade(CascadeType.SAVE_UPDATE)
    public Documento getDocumento() {
        return documento;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Movimento other = (Movimento) obj;
        if (this.movimentoPK != other.movimentoPK && (this.movimentoPK == null || !this.movimentoPK.equals(other.movimentoPK))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 47 * hash + (this.movimentoPK != null ? this.movimentoPK.hashCode() : 0);
        return hash;
    }
}

Também foi necessário mapear a classe MovimentoPK:

@Embeddable
public class MovimentoPK implements Serializable {

    private static final long serialVersionUID = 1l;
    private Integer documentoId;
    private Integer origemId;
    private Integer destinoId;
    private Date envio;

    ...

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MovimentoPK other = (MovimentoPK) obj;
        if (this.documentoId != other.documentoId && (this.documentoId == null || !this.documentoId.equals(other.documentoId))) {
            return false;
        }
        if (this.origemId != other.origemId && (this.origemId == null || !this.origemId.equals(other.origemId))) {
            return false;
        }
        if (this.destinoId != other.destinoId && (this.destinoId == null || !this.destinoId.equals(other.destinoId))) {
            return false;
        }
        if (this.envio != other.envio && (this.envio == null || !this.envio.equals(other.envio))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 89 * hash + (this.documentoId != null ? this.documentoId.hashCode() : 0);
        hash = 89 * hash + (this.origemId != null ? this.origemId.hashCode() : 0);
        hash = 89 * hash + (this.destinoId != null ? this.destinoId.hashCode() : 0);
        hash = 89 * hash + (this.envio != null ? this.envio.hashCode() : 0);
        return hash;
    }
}

Também foi necessário se realizar a seguinte consulta:

@Repository("documentoRepository")
public class DocumentoRepository extends GenericHibernateBasicRepository<Documento> {

    private static final long serialVersionUID = 1L;

    public DocumentoRepository() {
    }

    public Collection<Documento> getAllFromDocumentoFilterData(DocumentoFilterData documentoFilterData) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Documento.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        if (documentoFilterData.getIdDocumento() != null) {
            detachedCriteria.add(Restrictions.eq("id", documentoFilterData.getIdDocumento()));
        }
        detachedCriteria.addOrder(Order.desc("emissao"));
        return this.getAll(detachedCriteria);
    }

Ocorre que, ao se realizar a consulta o hibernate preenche a coleção de movimento na classe Documento com valores repetidos de Movimento. Utilizo o Criteria.DISTINCT_ROOT_ENTITY ResultTransformer, no entanto, não consigo recuper o objeto da forma correta. Alterei a interface da coleção(de List para Set). Resolveu o problema pois o Set não permite resultados duplicados, no entanto é muito ineficiente utilizar um Set pois eu preciso iterar pela coleção, além de acessar valores indexados. Sei que o hibernate se utiliza da interface da Coleção para recuperar a semântica da associação, no entanto, espero que ele não nos limite a escolher uma estrutura de dados menos adequada.

Agradeço desde já, se alguém puder me auxiliar, principalmente, com a consulta.

Criado 26 de abril de 2011
Respostas 0
Participantes 1