Pessoal,
Estou com um problema esquisito aqui. Tenho dois relacionamentos 1-N numa classe. Se utilizo a estrategia de fetch FetchType.LAZY, a coisa funciona legal, se utilizo FetchType.EAGER parece que o Hibernate “se confunde”. Provavelmente eu que confundi alguma coisa - mas nao consigo entender esse comportamento.
Em poucas palavras:
- Trazendo tudo com Query (FetchType.LAZY): OK
- Trazendo tudo com Query (FetchType.EAGER): OK
- Trazendo um objeto com Session.get (FetchType.LAZY): OK
- Trazendo um objeto com Session.get (FetchType.EAGER): Problema
Abaixo segue codigo das classes, tabelas geradas e a saida do teste:
Um cliente pode ter N carros e N imoveis:
[code]package teste;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = “cliente”)
public class Cliente {
private int id;
private String nome;
private List<Carro> carroList = new ArrayList<Carro>();
private List<Imovel> imovelList = new ArrayList<Imovel>();
@Id(generate = GeneratorType.AUTO)
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
@Column(name = "nome", nullable = false)
public String getNome() { return this.nome; }
public void setNome(String nome) { this.nome = nome; }
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "id_cliente")
public List<Carro> getCarroList() { return this.carroList; }
public void setCarroList(List<Carro> carroList) { this.carroList = carroList; }
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "id_cliente")
public List<Imovel> getImovelList() { return this.imovelList; }
public void setImovelList(List<Imovel> imovelList) { this.imovelList = imovelList; }
public boolean equals(Object o) {
return ((o instanceof Cliente) && (((Cliente)o).getId() == getId()));
}
public int hashCode() {
return new Integer(this.getId()).hashCode();
}
}[/code]
Carro:
[code]package teste;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = “carro”)
public class Carro {
private int id;
private String modelo;
@Id(generate = GeneratorType.AUTO)
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
@Column(name = "modelo", nullable = false)
public String getModelo() { return this.modelo; }
public void setModelo(String modelo) { this.modelo = modelo; }
public boolean equals(Object o) {
return ((o instanceof Carro) && (((Carro)o).getId() == getId()));
}
public int hashCode() {
return new Integer(this.getId()).hashCode();
}
}[/code]
Imovel:
[code]package teste;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = “imovel”)
public class Imovel {
private int id;
private String endereco;
@Id(generate = GeneratorType.AUTO)
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
@Column(name = "endereco", nullable = false)
public String getEndereco() { return this.endereco; }
public void setEndereco(String endereco) { this.endereco = endereco; }
public boolean equals(Object o) {
return ((o instanceof Imovel) && (((Imovel)o).getId() == getId()));
}
public int hashCode() {
return new Integer(this.getId()).hashCode();
}
}[/code]
Programinha pra testar esse cenario:
[code]package teste;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
public class Programa {
private static final SessionFactory sessionFactory =
new AnnotationConfiguration().configure("/resource/hibernate.cfg.xml")
.buildSessionFactory();
private void insert() throws Exception {
Cliente cliente1 = new Cliente(); cliente1.setNome("Cliente 1");
Cliente cliente2 = new Cliente(); cliente2.setNome("Cliente 2");
Carro c1 = new Carro(); c1.setModelo("Carro 1");
Carro c2 = new Carro(); c2.setModelo("Carro 2");
Carro c3 = new Carro(); c3.setModelo("Carro 3");
Carro c4 = new Carro(); c4.setModelo("Carro 4");
Imovel i1 = new Imovel(); i1.setEndereco("Imovel 1");
Imovel i2 = new Imovel(); i2.setEndereco("Imovel 2");
Imovel i3 = new Imovel(); i3.setEndereco("Imovel 3");
Imovel i4 = new Imovel(); i4.setEndereco("Imovel 4");
cliente1.setCarroList(Arrays.asList(new Carro[]{ c1, c2 }));
cliente1.setImovelList(Arrays.asList(new Imovel[]{ i1, i2 }));
cliente2.setCarroList(Arrays.asList(new Carro[]{ c3, c4 }));
cliente2.setImovelList(Arrays.asList(new Imovel[]{ i3, i4 }));
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(cliente1);
session.saveOrUpdate(cliente2);
tx.commit();
session.close();
}
private void search() throws Exception {
Session session = null;
session = sessionFactory.openSession();
Query query = session.createQuery("from Cliente c order by c.nome");
List list = query.list();
//session.close();
for (Object object : list) {
Cliente cliente = (Cliente)object;
System.err.println("-------------");
System.err.printf("%s (Carros: %d, Imoveis: %d)\n", cliente.getNome(),
cliente.getCarroList().size(), cliente.getImovelList().size());
for (Carro c : cliente.getCarroList()) {
System.err.printf(" Carro %d - %s\n", c.getId(), c.getModelo());
}
for (Imovel i : cliente.getImovelList()) {
System.err.printf(" Imovel %d - %s\n", i.getId(), i.getEndereco());
}
System.err.println("-------------");
}
session.close();
session = sessionFactory.openSession();
Cliente cliente = (Cliente)session.get(Cliente.class, new Integer(1));
//session.close();
System.err.println("-------------");
System.err.printf("%s (Carros: %d, Imoveis: %d)\n", cliente.getNome(),
cliente.getCarroList().size(), cliente.getImovelList().size());
for (Carro c : cliente.getCarroList()) {
System.err.printf(" Carro %d - %s\n", c.getId(), c.getModelo());
}
for (Imovel i : cliente.getImovelList()) {
System.err.printf(" Imovel %d - %s\n", i.getId(), i.getEndereco());
}
System.err.println("-------------");
session.close();
}
public static void main(String[] args) throws Exception {
Programa programa = new Programa();
programa.insert();
programa.search();
}
}[/code]
Tabelas e dados apos rodar o teste (tudo OK):
[code]mysql> select * from cliente; select * from carro; select * from imovel;
±—±----------+
| id | nome |
±—±----------+
| 1 | Cliente 1 |
| 2 | Cliente 2 |
±—±----------+
2 rows in set (0.00 sec)
±—±--------±-----------+
| id | modelo | id_cliente |
±—±--------±-----------+
| 1 | Carro 1 | 1 |
| 2 | Carro 2 | 1 |
| 3 | Carro 3 | 2 |
| 4 | Carro 4 | 2 |
±—±--------±-----------+
4 rows in set (0.00 sec)
±—±---------±-----------+
| id | endereco | id_cliente |
±—±---------±-----------+
| 1 | Imovel 1 | 1 |
| 2 | Imovel 2 | 1 |
| 3 | Imovel 3 | 2 |
| 4 | Imovel 4 | 2 |
±—±---------±-----------+
4 rows in set (0.00 sec)[/code]
Saida do programa utilizando a estrategia de fetch FetchType.LAZY (OK):
[code]-------------
Cliente 1 (Carros: 2, Imoveis: 2)
Carro 1 - Carro 1
Carro 2 - Carro 2
Imovel 1 - Imovel 1
Imovel 2 - Imovel 2
Cliente 2 (Carros: 2, Imoveis: 2)
Carro 3 - Carro 3
Carro 4 - Carro 4
Imovel 3 - Imovel 3
Imovel 4 - Imovel 4
Cliente 1 (Carros: 2, Imoveis: 2)
Carro 1 - Carro 1
Carro 2 - Carro 2
Imovel 1 - Imovel 1
Imovel 2 - Imovel 2
-------------[/code]
Saida do programa (apagando as tabelas), mas mudando o fetch para FetchType.EAGER (problema):
[code]-------------
Cliente 1 (Carros: 2, Imoveis: 2)
Carro 1 - Carro 1
Carro 2 - Carro 2
Imovel 1 - Imovel 1
Imovel 2 - Imovel 2
Cliente 2 (Carros: 2, Imoveis: 2)
Carro 3 - Carro 3
Carro 4 - Carro 4
Imovel 3 - Imovel 3
Imovel 4 - Imovel 4
Cliente 1 (Carros: 4, Imoveis: 4)
Carro 1 - Carro 1
Carro 1 - Carro 1
Carro 2 - Carro 2
Carro 2 - Carro 2
Imovel 1 - Imovel 1
Imovel 2 - Imovel 2
Imovel 1 - Imovel 1
Imovel 2 - Imovel 2
-------------[/code]
Se leu ate aqui, obrigado pela paciencia. 
Onde esta o erro? Algum problema conceitual? O manual do Hibernate Annotations diz que eh incomum e nao recomenda mapear 1-N colocando a FK na mesma tabela do lado N, mas nao consegui entender o porque - parece algo tao normal :).
Marcio Kuchma