it-swarm-pt.tech

Hibernate (JPA) como fazer uma consulta ansiosa, carregando todos os objetos filho

Em relação à minha pergunta anterior , desejo garantir que todos os objetos filhos sejam carregados, pois tenho vários threads que podem precisar acessar os dados (e, assim, evitar exceções de carregamento lento). Entendo que a maneira de fazer isso é usar a palavra-chave "buscar" na consulta (EJB QL). Como isso:

select distinct o from Order o left join fetch o.orderLines

Supondo um modelo com uma classe Order que possui um conjunto de OrderLines.

Minha pergunta é que a palavra-chave "distinta" parece ser necessária, caso contrário, parece que eu recebo um Order para cada OrderLine. Estou fazendo a coisa certa?

Talvez o mais importante seja, existe uma maneira de atrair todos os objetos filhos, não importa quão profundo? Temos entre 10 e 15 aulas e para o servidor precisaremos de tudo carregado ... Evitei usar FetchType.EAGER como isso significa que está sempre ansioso e, em particular, o front-end da Web carrega tudo - mas talvez esse seja o caminho - é isso que você faz? Parece que me lembro de ter tentado isso antes e depois ter páginas da web muito lentas - mas talvez isso signifique que deveríamos estar usando um cache de segundo nível?

20
Chris Kimpton

Alterar a anotação é uma má ideia IMO. Como não pode ser alterado para lento no tempo de execução. Melhor tornar tudo preguiçoso e buscar conforme necessário.

Não sei se entendi o seu problema sem mapeamentos. A busca de junção esquerda deve ser tudo o que você precisa para o caso de uso que você descreve. É claro que você receberá de volta um pedido para cada linha de pedido se a linha de pedido tiver um pedido como pai.

14
James Law

Não tenho certeza sobre o uso da palavra-chave buscar em seu EJBQL, você pode estar confundindo-a com a anotação ...

Você já tentou adicionar a propriedade FetchType ao seu atributo de relacionamento?

@OneToMany (buscar = FetchType.EAGER)?

Vejo:

http://Java.Sun.com/javaee/5/docs/api/javax/persistence/FetchType.htmlhttp://www.jroller.com/eyallupu/entry/ hibernate_exception_simultaneamente_fetch_multiple

8
Jeremy

Você já tentou usar um transformador de resultado? Se você usar consultas de Critérios, poderá aplicar um transformador de resultado (embora haja alguns problemas com paginação e transformador de resultado ):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class);
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.list();

o em.getDelegate() é um hack que só funciona se você estiver usando o hibernate.

Talvez o mais importante seja que haja uma maneira de atrair todos os objetos filhos, não importa a profundidade? Temos entre 10 e 15 aulas e, para o servidor, precisaremos de tudo carregado ... Evitei usar o FetchType.EAGER, pois isso significa que está sempre ansioso e, em particular, o front-end da Web carrega tudo - mas talvez esse seja o caminho a seguir - É isso o que você faz? Eu me lembro de ter tentado isso antes e depois ter páginas muito lentas - mas talvez isso signifique que deveríamos estar usando um cache de segundo nível?

Se você ainda estiver interessado, respondi a uma pergunta semelhante neste tópico como serializar coleções de hibernação .

Basicamente, você usa um utilitário chamado dozer que mapeia beans para outros beans e, ao fazer isso, você aciona todas as suas cargas preguiçosas. Como você pode imaginar, isso funciona melhor se todas as coleções forem buscadas ansiosamente.

3
Miguel Ping

Você pode fazer algo assim usando uma consulta de critérios (desanexada) e definindo o modo de busca. Por exemplo.,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession();
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id));
dc.setFetchMode("innerTable", FetchMode.JOIN);
Criteria c = dc.getExecutableCriteria(s);
MyEntity a = (MyEntity)c.uniqueResult();
2
Mike Desjardins

O que fiz foi refatorar o código para manter um mapa de objetos para os gerentes de entidade e toda vez que eu precisar atualizar, feche o gerenciador de entidades antigo do objeto e abra um novo. Eu usei a consulta acima sem o buscar, pois isso está indo muito fundo para minhas necessidades - apenas fazendo um simples puxar de junção nos OrderLines - o buscar torna ainda mais profundo.

Existem apenas alguns objetos para os quais preciso, por volta de 20, então acho que a sobrecarga de recursos em ter 20 gerenciadores de entidades abertos não é um problema - embora os DBAs possam ter uma visão diferente quando isso for lançado ...

Também refiz as coisas para que o trabalho do banco de dados esteja no segmento principal e tenha o gerente da entidade.

Chris

0
Chris Kimpton

Isso funcionaria apenas para as relações ManyToOne e, para elas, @ManyToOne (fetch = FetchType.EAGER) provavelmente seria apropriado.

A busca de mais de uma relação OneToMany é desencorajada e/ou não funciona, como você pode ler no link publicado por Jeremy. Basta pensar na instrução SQL que seria necessária para fazer essa busca ...

0
jrudolph