Dúvida sobre OneToMany no Hibernate

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?

Quando a relação é simples, eu faço assim

@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.