Bom, tenho o seguinte relacionamento: Orcamento -> Itens. Cada orçamento pode ter diversos itens. Minha dúvida é como fazer um HQL que retorne o objeto orcamento popula com seus itens, algo como isso:
SELECT c FROM Orcamento c JOIN FETCH c.itens
Acontece que se o Orçamento tiver 4 itens, ele irá retornar 4 linhas no HQL acima, quando deveria retornar só 1, que é o objeto ORçamento populado com esses 4 itens.
vai dar plano cartesiano se fizer assim,o certo é fazer um só para orçamento e outro só para itens,
a não ser que no hibernate tenha alguma ferramenta que ajude,até porque to começando em jpa e hibernate tmb…
no jdbc eu fazia um for só do orçamento,e na mesma tela colocava outro for para os itens também
***orçamento não seria for ,só os itens do orçamento
Se itens é a denominação de um atributo de Orcamento, basta fazer:
SELECT o FROM Orcamento o
Ele trará todos os orçamentos e todos os atributos do mesmo.
Partindo daí, você precisa ver se o mapeamento de itens está como Lazy ou Eager e como você está gerenciando a sessão (se open session in view ou não).
[quote=drsmachado]Se itens é a denominação de um atributo de Orcamento, basta fazer:
SELECT o FROM Orcamento o
Ele trará todos os orçamentos e todos os atributos do mesmo.
Partindo daí, você precisa ver se o mapeamento de itens está como Lazy ou Eager e como você está gerenciando a sessão (se open session in view ou não).[/quote]
Em alguns casos você pode ter o relacionamento mapeado como lazy e, em uma consulta específica, querer carregá-lo em modo eager, por questões de desempenho. Neste caso, faz sentido o hql do rlanhellas. Mas pra evitar os resultados duplicados, pode-se utilizar distinct:
Neste caso, o hibernate aplica um result transformer e remove as duplicações (é como aplicar o DISTINCT_ROOT_ENTITY numa criteria).
[quote=wagnerfrancisco][quote=drsmachado]Se itens é a denominação de um atributo de Orcamento, basta fazer:
SELECT o FROM Orcamento o
Ele trará todos os orçamentos e todos os atributos do mesmo.
Partindo daí, você precisa ver se o mapeamento de itens está como Lazy ou Eager e como você está gerenciando a sessão (se open session in view ou não).[/quote]
Em alguns casos você pode ter o relacionamento mapeado como lazy e, em uma consulta específica, querer carregá-lo em modo eager, por questões de desempenho. Neste caso, faz sentido o hql do rlanhellas. Mas pra evitar os resultados duplicados, pode-se utilizar distinct:
Neste caso, o hibernate aplica um result transformer e remove as duplicações (é como aplicar o DISTINCT_ROOT_ENTITY numa criteria).[/quote]
Numa consulta com lazy, a partir da invocação do atributo desejado, ele será carregado, não?
Não gosto de distinct, me lembra que meus filtros estão incorretos…
wagnerfrancisco é exatamente isso que eu queria saber, o distinct resolve meu problema.
drsmachado a sua questão também me intrigou, quando vocẽ diz "Numa consulta com lazy, a partir da invocação do atributo desejado, ele será carregado, não? ". Eu fiz esse teste e ao tentar acessar os itens eu recebo NULL, ou seja, eles não são carregados “por demanda”.
[quote=drsmachado]
Numa consulta com lazy, a partir da invocação do atributo desejado, ele será carregado, não?
Não gosto de distinct, me lembra que meus filtros estão incorretos…[/quote]
Sim, ele será carregado, mas aí você vai acessar o banco novamente e fazer novas queries. Forçando o modo eager ele faz o join e traz tudo de uma vez. Se tiver problemas de desempenho, pode ser interessante.
Um outro uso que eu fiz deste recurso foi num projeto integrado ao Flex e Spring. Na hora de serializar os objetos para o Flex, o Spring tinha um recurso que permitia ignorar os proxies do Hibernate, pra evitar enviar todo o objeto pro cliente. O problema é que se eu quisesse enviar os dados, teria que carregá-los. Melhor fazer isto direto na query do que acessar os objetos só pra fazer o carregamento.
Quanto ao distinct, não vejo problemas neste caso, uma vez que o objetivo é fazer o Hibernate remover os duplicados através de um ResultTransformer e não produzir uma query com distinct (embora isto possa vir a acontecer!).
[quote=rlanhellas]wagnerfrancisco é exatamente isso que eu queria saber, o distinct resolve meu problema.
drsmachado a sua questão também me intrigou, quando vocẽ diz "Numa consulta com lazy, a partir da invocação do atributo desejado, ele será carregado, não? ". Eu fiz esse teste e ao tentar acessar os itens eu recebo NULL, ou seja, eles não são carregados “por demanda”.[/quote]
Como você fez a consulta e como está o objeto cujos atributos não foram carregados?
@Entity
public class Endereco implements Serializable{
@Id
@GeneratedValue
private Long id;
//outros atributos
//getters e setters
}
//
@Entity
public class Cliente implements Serializable{
@ManyToMany(targetEntity=Endereco.class)
private Set<Endereco> enderecos;
//Demais atributos
//getters e setters
}
E, ao fazer:
String hql = "SELECT c FROM Cliente c";
//Todo o resto aqui
Eu obteno todos os clientes e todos os endereços atrelados a eles.
[quote=wagnerfrancisco][quote=drsmachado]
Numa consulta com lazy, a partir da invocação do atributo desejado, ele será carregado, não?
Não gosto de distinct, me lembra que meus filtros estão incorretos…[/quote]
Sim, ele será carregado, mas aí você vai acessar o banco novamente e fazer novas queries. Forçando o modo eager ele faz o join e traz tudo de uma vez. Se tiver problemas de desempenho, pode ser interessante.
Um outro uso que eu fiz deste recurso foi num projeto integrado ao Flex e Spring. Na hora de serializar os objetos para o Flex, o Spring tinha um recurso que permitia ignorar os proxies do Hibernate, pra evitar enviar todo o objeto pro cliente. O problema é que se eu quisesse enviar os dados, teria que carregá-los. Melhor fazer isto direto na query do que acessar os objetos só pra fazer o carregamento.
Quanto ao distinct, não vejo problemas neste caso, uma vez que o objetivo é fazer o Hibernate remover os duplicados através de um ResultTransformer e não produzir uma query com distinct (embora isto possa vir a acontecer!).
[/quote]
Eu não gosto do distinct justamente por pensar que eu poderia evitá-lo usando uma query melhorada. Lógico que ele vai ser necessário em alguma situação, porém, é bem raro.
A questão é identificar o que é menos impactante ao sistema: várias consultas ou manter os dados em memória, mesmo sem utilizá-los. Por isso lazy e eager são opções e não imposições.