[RESOLVIDO] Hibernate Criteria - Lista trazendo registros duplicados

5 respostas
R

Olá Pessoal!

Estou com um problema ao utilizar criteria em apenas um objeto (acreditem se quiser).

A princípio o objeto é simples. Segue abaixo:

Cargo

@Entity
@Table(name="tb_cargo")
public class Cargo {
	
	private Long id;
	private String nome;
	private String descricao;
	private Date dataAtivacao;
	private Date dataInativacao;
	
	//Niveis de ,Acesso Para o Cargo do Colaborador
	private List<MetodoController> metodosController;
	
	@Id
	@GeneratedValue
	@Column(name="id_cargo")
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	
	@Column(length=100, nullable=false)
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	@Column(length=100, nullable=true)
	public String getDescricao() {
		return descricao;
	}
	public void setDescricao(String descricao) {
		this.descricao = descricao;
	}
	
	@ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
	@JoinTable(name="tb_metodo_controller_cargo", 
				joinColumns=@JoinColumn(name="id_cargo"), 
				inverseJoinColumns=@JoinColumn(name="id_metodo_controller"))
	public List<MetodoController> getMetodosController() {
		return metodosController;
	}
	public void setMetodosController(List<MetodoController> metodosController) {
		this.metodosController = metodosController;
	}

	@Column(nullable=false)
	@Temporal(TemporalType.DATE)
	public Date getDataAtivacao() {
		return dataAtivacao;
	}
	public void setDataAtivacao(Date dataAtivacao) {
		this.dataAtivacao = dataAtivacao;
	}
	
	@Column(nullable=true)
	@Temporal(TemporalType.DATE)
	public Date getDataInativacao() {
		return dataInativacao;
	}
	public void setDataInativacao(Date dataInativacao) {
		this.dataInativacao = dataInativacao;
	}
}

DAO - Estamos usando uma classe genérica, mas já realizei testes na classe DAO própria

public List<T> listar(T object){
		List<T> objects = new ArrayList<T>(); 
		criteria = session.createCriteria(object.getClass());
		criteria.add(Restrictions.isNull("dataInativacao"));
		objects = criteria.list();
		return objects;
	}

Classe Teste de Listagem

private static void listarCargo(Session session) {
		List<Cargo> cargos = new ArrayList<Cargo>();
		CargoDAO cargoDao = new CargoDAO(session);
		
		cargos = cargoDao.listar(new Cargo());
		
		System.out.println("Existem " + cargos.size() +" cargos cadastrados");
		
		for(Cargo cargo : cargos){
			
			for(MetodoController metodoController : cargos.get(1).getMetodosController()){
				System.out.println("Cargo: " + cargos.get(1).getNome() + " | MetodoControllerCargo " + metodoController.getId() + "=> Controller:  " + metodoController.getController().getNome() + " | Metodo: " + metodoController.getMetodo().getNome());
			}
		}
	}

Output do console

Existem 2 cargos cadastrados
Cargo: Promotor | MetodoControllerCargo 1=> Controller:  CargoController | Metodo: carregaCadastrar
Cargo: Promotor | MetodoControllerCargo 2=> Controller:  CargoController | Metodo: cadastrar
Cargo: Promotor | MetodoControllerCargo 1=> Controller:  CargoController | Metodo: carregaCadastrar
Cargo: Promotor | MetodoControllerCargo 2=> Controller:  CargoController | Metodo: cadastrar

Na base de dados, apenas um cargo está cadastrado (caso perguntem: tenho certeza disso!).

Não consegui identificar o que estou fazendo de errado. Alguém poderia me dar uma luz?

Obrigado! :slight_smile:

5 Respostas

J

Mostre o SQL gerado pelo Hibernate.

R

Segue:

Hibernate: 
    select
        this_.id_cargo as id1_10_3_,
        this_.dataAtivacao as dataAtiv2_10_3_,
        this_.dataInativacao as dataInat3_10_3_,
        this_.descricao as descricao10_3_,
        this_.nome as nome10_3_,
        metodoscon2_.id_cargo as id1_10_5_,
        metodocont3_.id_metodo_controller as id2_5_,
        metodocont3_.id_metodo_controller as id1_49_0_,
        metodocont3_.id_controller as id2_49_0_,
        metodocont3_.id_metodo as id3_49_0_,
        controller4_.id_controller as id1_16_1_,
        controller4_.nome as nome16_1_,
        controller4_.nomeExibicao as nomeExib3_16_1_,
        controller4_.tipoController as tipoCont4_16_1_,
        metodo5_.id_metodo as id1_48_2_,
        metodo5_.nome as nome48_2_,
        metodo5_.nomeExibicao as nomeExib3_48_2_,
        metodo5_.tipoMetodo as tipoMetodo48_2_ 
    from
        tb_cargo this_ 
    left outer join
        tb_metodo_controller_cargo metodoscon2_ 
            on this_.id_cargo=metodoscon2_.id_cargo 
    left outer join
        tb_metodo_controller metodocont3_ 
            on metodoscon2_.id_metodo_controller=metodocont3_.id_metodo_controller 
    left outer join
        tb_controller controller4_ 
            on metodocont3_.id_controller=controller4_.id_controller 
    left outer join
        tb_metodo metodo5_ 
            on metodocont3_.id_metodo=metodo5_.id_metodo 
    where
        this_.dataInativacao is null
Hibernate: 
    select
        metodoscon0_.id_controller as id2_16_2_,
        metodoscon0_.id_metodo_controller as id1_2_,
        metodoscon0_.id_metodo_controller as id1_49_1_,
        metodoscon0_.id_controller as id2_49_1_,
        metodoscon0_.id_metodo as id3_49_1_,
        metodo1_.id_metodo as id1_48_0_,
        metodo1_.nome as nome48_0_,
        metodo1_.nomeExibicao as nomeExib3_48_0_,
        metodo1_.tipoMetodo as tipoMetodo48_0_ 
    from
        tb_metodo_controller metodoscon0_ 
    inner join
        tb_metodo metodo1_ 
            on metodoscon0_.id_metodo=metodo1_.id_metodo 
    where
        metodoscon0_.id_controller=?
Hibernate: 
    select
        metodoscon0_.id_controller as id2_16_2_,
        metodoscon0_.id_metodo_controller as id1_2_,
        metodoscon0_.id_metodo_controller as id1_49_1_,
        metodoscon0_.id_controller as id2_49_1_,
        metodoscon0_.id_metodo as id3_49_1_,
        metodo1_.id_metodo as id1_48_0_,
        metodo1_.nome as nome48_0_,
        metodo1_.nomeExibicao as nomeExib3_48_0_,
        metodo1_.tipoMetodo as tipoMetodo48_0_ 
    from
        tb_metodo_controller metodoscon0_ 
    inner join
        tb_metodo metodo1_ 
            on metodoscon0_.id_metodo=metodo1_.id_metodo 
    where
        metodoscon0_.id_controller=?
J

Como você pode ver no SQL os joins com tabelas “metodo” fizeram o cargo duplicar para cada metodo. Não entendo muito de mapeamento por annotation mas provavelmente foi devido voce ter usado fetch em seu mapeamento. Você pode retirar o fetch do mapeamento e usar o fetch quando necessitar via Criteria por exemplo, assim poderia usar o Cargo diretamente sem Criteria. Mas caso precise manter do jeito que está, a solução é adicionar isso na sua criteria:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

R

Muito obrigado javaflex!

Acabei esquecendo de responder aqui, hehe :slight_smile:

J

RKrum:
Muito obrigado javaflex!

Acabei esquecendo de responder aqui, hehe :)


Valeu! Só procure não usar em todos os casos Fetch Eager no mapeamento, pois pode ter muitos casos que nem sempre irá acessar este atributo, onde se precisasse só ler o nome do cargo por exemplo esse SQL gigante indo em várias tabelas seria executado sem necessidade. Mais detalhes nesse post: http://www.guj.com.br/java/273447-criteria-trazendo-resultados-duplicados/2#1555593

Criado 2 de fevereiro de 2013
Ultima resposta 16 de fev. de 2013
Respostas 5
Participantes 2