@SecondaryTable

4 respostas
tiagoemerick

Pessoal,

recentemente eu precisei mapear a minha classe com o @SecondaryTable do javax.persistence.
Para o que eu queria funcionou perfeitamente, mas em troca disso os registros estão vindo duplicados!

Debugando o SQL gerado eu percebi que ele faz um left outer join com a tabela do SecondaryTable, por isso traz os registros duplicados quando eu faço um find, por exemplo.

Alguém tem alguma idéia de como corrigir?
O javax.persistence.* oferece algo para corrigir isso?

Segue minha classe mapeada e o SQL gerado:

import java.util.ArrayList;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.CollectionOfElements;
import org.jboss.seam.annotations.Name;

@Entity
@Table(name = "PRC_ITNO")
@Name("processoInterno")
@SecondaryTables({
	@SecondaryTable(name = "ITC_NRMV_PRC_ITNO", pkJoinColumns = {
			@PrimaryKeyJoinColumn(referencedColumnName = "CD_PRC_ITNO", name = "CD_PRC_ITNO")
	})
})
public class ProcessoInterno extends AbstractEntityAuditavel<Long> {

	private String nome;
	private Periodo periodoVigencia;
	private List<InstrucaoNormativa> instrucoesNormativas;
	private List<Atividade> atividades;
	private Integer areaInteresse;
	private Integer cdProcessoInternoInstrucaoNormativa;
	private Long cdInstrucaoNormativaProcessoInterno;
	
	@Override
	@Id
	@GeneratedValue
	@Column(name = "CD_PRC_ITNO")
	public Long getId() {
		return super.getId();
	}

	@Column(name = "NM_PRC_ITNO")
	public String getNome() {
		if (this.nome != null) {
			this.nome = this.nome.trim();
		}
		return this.nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
	
	public void addInstrucaoNormativa(InstrucaoNormativa in) {
	    if (instrucoesNormativas == null) instrucoesNormativas = new ArrayList<InstrucaoNormativa>();
	    instrucoesNormativas.add(in);
	}

	@Embedded
	@AttributeOverrides ( {
			@AttributeOverride (name="dataInicio", column=@Column(name="DT_INC_VGC_PRC")),
			@AttributeOverride (name="dataFim", column=@Column(name="DT_FIM_VGC_PRC"))
		}	
	)
	public Periodo getPeriodoVigencia() {
		if (this.periodoVigencia == null) {
			this.periodoVigencia = new Periodo();
		}
		return this.periodoVigencia;
	}

	public void setPeriodoVigencia(Periodo periodoVigencia) {
		this.periodoVigencia = periodoVigencia;
	}

	@OneToMany(mappedBy = "processoInterno", fetch=FetchType.LAZY)
	public List<Atividade> getAtividades() {
		return this.atividades;
	}

	public void setAtividades(List<Atividade> atividades) {
		this.atividades = atividades;
	}

	@CollectionOfElements (fetch=FetchType.LAZY)
    @JoinTable(
            name="ITC_NRMV_PRC_ITNO",
            joinColumns = @JoinColumn(name="CD_PRC_ITNO")
    )
    @AttributeOverride (column=@Column(name="CD_ITC_NRMV"), name="element.longForm")
	public List<InstrucaoNormativa> getInstrucoesNormativas() {
		if (instrucoesNormativas == null)
			instrucoesNormativas = new ArrayList<InstrucaoNormativa>();
		return instrucoesNormativas;
	}

	public void setInstrucoesNormativas(List<InstrucaoNormativa> instrucoesNormativas) {
		this.instrucoesNormativas = instrucoesNormativas;
	}

	@Column(name = "CD_AREA_ITSE")
	public Integer getAreaInteresse() {
		return areaInteresse;
	}

	public void setAreaInteresse(Integer areaInteresse) {
		this.areaInteresse = areaInteresse;
	}
	
	@Column(table = "ITC_NRMV_PRC_ITNO", insertable = false, updatable = false, name = "CD_PRC_ITNO")
	public Integer getCdProcessoInternoInstrucaoNormativa() {
		return cdProcessoInternoInstrucaoNormativa;
	}

	public void setCdProcessoInternoInstrucaoNormativa(Integer cdProcessoInternoInstrucaoNormativa) {
		this.cdProcessoInternoInstrucaoNormativa = cdProcessoInternoInstrucaoNormativa;
	}
	
	@Column(table = "ITC_NRMV_PRC_ITNO", insertable = false, updatable = false, name = "CD_ITC_NRMV")
	public Long getCdInstrucaoNormativaProcessoInterno() {
		return cdInstrucaoNormativaProcessoInterno;
	}

	public void setCdInstrucaoNormativaProcessoInterno(Long cdInstrucaoNormativaProcessoInterno) {
		this.cdInstrucaoNormativaProcessoInterno = cdInstrucaoNormativaProcessoInterno;
	}

	@Transient
	public String getAreaInteresseStr() {
	    return EnumAreaInteresse.find(areaInteresse).getDescription();
	}

	public String toString() {
		return "ProcessoInterno [ id = " + getId() + ", nome = " + nome + ", periodoVigencia = " + periodoVigencia + "]";
	}

	@Override
	public int hashCode() {
		if (getId() != null)
			return getId().hashCode();
		return -1;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!super.equals(obj)) {
			return false;
		}
		if (!(obj instanceof ProcessoInterno)) {
			return false;
		}
		ProcessoInterno other = (ProcessoInterno) obj;
		if (getId() == null) {
			if (other.getId() != null) {
				return false;
			}
		} else if (!getId().equals(other.getId())) {
			return false;
		}
		return true;
	}

}
select
        processoin0_.CD_PRC_ITNO as CD1_4_,
        processoin0_.CD_AREA_ITSE as CD2_4_,
        processoin0_.NM_PRC_ITNO as NM3_4_,
        processoin0_.DT_FIM_VGC_PRC as DT4_4_,
        processoin0_.DT_INC_VGC_PRC as DT5_4_,
        processoin0_1_.CD_ITC_NRMV as CD1_5_,
        processoin0_1_.CD_PRC_ITNO as CD2_5_ 
    from
        DB2WFJDEV.PRC_ITNO processoin0_ 
    left outer join
        DB2WFJDEV.ITC_NRMV_PRC_ITNO processoin0_1_ 
            on processoin0_.CD_PRC_ITNO=processoin0_1_.CD_PRC_ITNO

4 Respostas

partenon

A query esta correta, ele deve mesmo fazer um left outer join. A pergunta na verdade eh pq existem dois registros na tabela ITC_NRMV_PRC_ITNO para um registro na tabela PRC_ITNO. Essa relacao deveria ser de 1-1, mas parece que nao eh o caso.

tiagoemerick

Não é de 1-1.
De fato a SecondaryTable é uma N:N.

Realmente a query não está errada. Na verdade eu queria um modo de fazer a pesquisa na tabela principal sem o join.
É possível ou esse secondaryTable serve apenas para 1-1?

partenon

SecondaryTable eh para utilizar quando vc quer, por motivos de performance no lado do banco de dados, separar os grandes dados em varias tabelas (por exemplo, para manter “lobs” pouco utilizados em outras tabelas). Entao, o SecondaryTable nao me parece ser a solucao para seu problema.

Mas nao entendi o que deseja. Se os dados estao em outras tabelas, e estas tabelas tem um relacionamento N-N, pq nao cria uma outra entidade com o relacionamento correto? :slight_smile: Acho que nao estou conseguindo entender direito seu problema.

tiagoemerick

É… acho que a solução é recriar o relacionamento usando o NomeRelacionamentoID.

Achei que dessa forma não teria problemas.
Que de alguma forma, eu teria como manipular esse left join sem gambis.

Melhor fazer correto.

Valeu pela ajuda!!

Criado 28 de junho de 2010
Ultima resposta 28 de jun. de 2010
Respostas 4
Participantes 2