JPA + Eclipse Link

5 respostas
I

Pessoal, gostaria da ajuda de vocês para entender o seguinte problema:

Classes mapeadas:

/**

  • The persistent class for the tb_area database table.
*/

@Entity

@Table(name=tb_area)

public class TbArea implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@Column(name="id_area")
private Integer idArea;

@Column(name="nm_area", nullable=false, length=50)
private String nmArea;

@Column(name="sg_area", nullable=false, length=10)
private String sgArea;

//bi-directional many-to-one association to TbArea
@ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="id_area_pai")
private TbArea tbArea;

//bi-directional many-to-one association to TbArea
@OneToMany(mappedBy="tbArea", cascade={CascadeType.ALL})
private List<TbArea> tbAreas;

//bi-directional many-to-one association to TbOrganizacao
@ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name="id_organizacao")
private TbOrganizacao tbOrganizacao;

public TbArea() {
}

public Integer getIdArea() {
	return this.idArea;
}

public void setIdArea(Integer idArea) {
	this.idArea = idArea;
}

public String getNmArea() {
	return this.nmArea;
}

public void setNmArea(String nmArea) {
	this.nmArea = nmArea;
}

public String getSgArea() {
	return this.sgArea;
}

public void setSgArea(String sgArea) {
	this.sgArea = sgArea;
}

public TbArea getTbArea() {
	return this.tbArea;
}

public void setTbArea(TbArea tbArea) {
	this.tbArea = tbArea;
}

public List<TbArea> getTbAreas() {
	return this.tbAreas;
}

public void setTbAreas(List<TbArea> tbAreas) {
	this.tbAreas = tbAreas;
}

public TbOrganizacao getTbOrganizacao() {
	return this.tbOrganizacao;
}

public void setTbOrganizacao(TbOrganizacao tbOrganizacao) {
	this.tbOrganizacao = tbOrganizacao;
}

}

e

/**

  • The persistent class for the tb_organizacao database table.
*/

@Entity

@Table(name=tb_organizacao)

public class TbOrganizacao implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@Column(name="id_organizacao", unique=true, nullable=false)
private int idOrganizacao;

@Column(name="nm_organizacao", nullable=false, length=50)
private String nmOrganizacao;

//bi-directional many-to-one association to TbArea
@OneToMany(mappedBy="tbOrganizacao")
private List<TbArea> tbAreas;

public TbOrganizacao() {
}

public int getIdOrganizacao() {
	return this.idOrganizacao;
}

public void setIdOrganizacao(int idOrganizacao) {
	this.idOrganizacao = idOrganizacao;
}

public String getNmOrganizacao() {
	return this.nmOrganizacao;
}

public void setNmOrganizacao(String nmOrganizacao) {
	this.nmOrganizacao = nmOrganizacao;
}

public List<TbArea> getTbAreas() {
	return this.tbAreas;
}

public void setTbAreas(List<TbArea> tbAreas) {
	this.tbAreas = tbAreas;
}

}

Executo a seguinte query:

final String sqlInicial = “select new spread.saf.entidades.RsManterArea(a.nmArea,a.tbArea,a.tbOrganizacao)from TbArea a”;

Queria pegar todos os dados que estão na TbArea, no entando observo o console e a seguinte consulta é gerada:

SELECT t0.nm_area, t1.id_area, t1.nm_area, t1.sg_area, t1.id_organizacao, t1.id_area_pai, t2.id_organizacao, t2.nm_organizacao FROM tb_area t0 LEFT OUTER JOIN tb_area t1 ON (t1.id_area = t0.id_area_pai) LEFT OUTER JOIN tb_organizacao t2 ON (t2.id_organizacao = t0.id_organizacao)

Minha dúvida: Por que é gerado os left outer joins, sendo que solicitei apenas os dados da TbArea? Ou seja não precisava fazer join com a TbOrganizacao e nem o join com a própria TbArea que possui um auto relacionamento.

Obrigado!

5 Respostas

Flavio_Almeida

Por default, relacionamento @ManyToOne é eager, ou seja, quando você consultar área, o objeto área retornado terá os valores dos relacionamentos @ManyToOne, por isso os left join realizados.

Se você achar isso ruim, você pode forçar que estes valores sejam do tipo Lazzy e não eager.
Ex.: @ManyToOne(fetch=FetchType.LAZY)

Olhando seu código novamente, vi que você já está fazendo uso deste recurso e, na teoria, era para ter funcionado.

Se você estiver usando o Glassfish, bem, a coisa fica difícil, pois abandonamos este servidor de aplicação devido ao grande número de bugs nas versões atuais.

Veja se isso pode ter ajudar: http://forums.java.net/jive/thread.jspa?messageID=389324

I

Olá Flávio!

Obrigado por responder! Para meu desespero quando realizo o teste da classe de acesso a dados eu ainda nem estou usando o servidor web e sim realizo o teste de uma classe main, ou seja, no modo java application.

veja o método que é chamado da classe main:

public List consultarAreas(Integer firstResult, Integer maxResult){

final String sqlInicial = "select new empresa.sistema.entidades.RsManterArea(a.nmArea,a.tbArea,a.tbOrganizacao)from TbArea a";
	Query que = em.createQuery(sqlInicial);		
	que.setFirstResult(firstResult);
	que.setMaxResults(maxResult);		
	//Query que = preparaConsulta(filtroConsultaProposta, sqlInicial, orderBy);
	return que.getResultList();

}

obrigado,
Igor

Flavio_Almeida

Colega, desconfio o que esteja acontecendo:

Na sua consulta, você NÃO RETORNA UMA ENTIDADE área, você retorna parte dela e usa um “result transformer” para criar uma instância de uma classe criada por você. Quando você faz isso, o EclipseLink não é capaz de criar um proxy, ou seja, um objeto falso que representa a entidade área. Quando área é acessada via proxy e ela possui um atributo FetchType=Lazy, o provider JPA só realiza a consulta quando você vai acessar o atributo da entidade.

Quando você faz isso a.nmArea,a.tbArea,a.tbOrganizacao, você está pinçando apenas alguns campos da entidade, desta forma, o JPA instancia sua classe e não sabe criar um proxy sobre ela.

Experimente realizar o teste: no lugar de executar a consulta como você fez, fala “from Area” só e veja como se comporta a consulta.

Veja o que acontece, pois também tenho interesse no resultado, visto que você utiliza EclipseLink e nossa empresa Hibernate.

I

Olá Flávio!

E o seguinte, tentei efetuar os testes que você me recomendou, no entanto não funcionou com “From TbArea” e sim com “Select a From TbArea a”. Ou seja efetuando a consulta ao objeto desta maneira, o eclipse link não realiza os outers joins e sim efetua os seguintes “selects”:

EL Fine]: 2010-10-13 23:20:35.918ServerSession(9363478)Connection(3403998)Thread(Thread[main,5,main])SELECT id_area, nm_area, sg_area, id_organizacao, id_area_pai FROM tb_area

[EL Fine]: 2010-10-13 23:20:35.955ServerSession(9363478)Connection(3445873)Thread(Thread[main,5,main])SELECT id_organizacao, nm_organizacao FROM tb_organizacao WHERE (id_organizacao = ?)

bind => [1]

[EL Fine]: 2010-10-13 23:20:35.971ServerSession(9363478)Connection(3403998)Thread(Thread[main,5,main])SELECT id_organizacao, nm_organizacao FROM tb_organizacao WHERE (id_organizacao = ?)

bind => [2]

[EL Fine]: 2010-10-13 23:20:35.973ServerSession(9363478)Connection(3445873)Thread(Thread[main,5,main])SELECT id_organizacao, nm_organizacao FROM tb_organizacao WHERE (id_organizacao = ?)

bind => [3]

Só não consegui entender porque quando realizo a consulta desta maneira "select new empresa.teste.entidades.RsManterArea(a.nmArea,a.tbArea,a.tbOrganizacao)from TbArea a ele realiza os outer joins.

Abraço

Flavio_Almeida

Essa semana as coisas estão bem puxadas aqui no trabalho, apesar disso, vou monitorar esse tópico e assim que eu tiver alguma posição nova sobre assunto, eu posto aqui.

Criado 12 de outubro de 2010
Ultima resposta 14 de out. de 2010
Respostas 5
Participantes 2