Hibernate (JPA) comment effectuer une requête rapide en chargeant tous les objets enfants

StackOverflow https://stackoverflow.com/questions/70992

  •  09-06-2019
  •  | 
  •  

Question

Relativement à ma question précédente , je souhaite m'assurer que tous les objets enfants sont chargés car j'ai plusieurs threads qui peuvent avoir besoin d'accéder aux données (et donc d'éviter les exceptions de chargement paresseux). Je comprends que la façon de faire est d’utiliser le " fetch " mot-clé dans la requête (EJB QL). Comme ceci:

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

Supposons un modèle avec une classe Order contenant un ensemble de OrderLines .

Ma question est que le " distinct " le mot clé semble être nécessaire, sinon, il me semble récupérer un Commande pour chaque OrderLine . Est-ce que je fais la bonne chose?

Peut-être plus important encore, y at-il un moyen d’attirer tous les objets enfants, quelle que soit leur profondeur? Nous avons environ 10-15 classes et pour le serveur nous aurons besoin de tout charger ... J'évitais d'utiliser FetchType.EAGER car cela signifiait qu'il était toujours désireux et en particulier que le Web frontal chargeait tout - mais c'est peut-être la voie à suivre - est-ce ce que vous faites? Il semble que je me souvienne de nous avoir déjà essayé cela avant d’avoir des pages Web vraiment lentes - mais peut-être que cela signifie que nous devrions utiliser un cache de second niveau?

Était-ce utile?

La solution

Changer l’annotation est une mauvaise idée, IMO. Comme il ne peut pas être changé en paresseux au moment de l'exécution. Mieux vaut tout rendre paresseux et aller chercher au besoin.

Je ne suis pas sûr de comprendre votre problème sans mappages. L'extraction de jointure gauche doit suffire à votre cas d'utilisation. Bien sûr, vous recevrez une commande pour chaque ligne de commande si cette dernière a une commande comme parent.

Autres conseils

Je ne suis pas sûr d'utiliser le mot clé fetch dans votre EJBQL, vous pourriez le confondre avec l'annotation ...

Avez-vous essayé d'ajouter la propriété FetchType à votre attribut de relation?

@OneToMany (fetch = FetchType.EAGER)?

Voir:

http://java.sun.com/ javaee / 5 / docs / api / javax / persistence / FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_exception_simultanée_fimiter_multiple

Avez-vous essayé d'utiliser un transformateur de résultat? Si vous utilisez des requêtes Critères, vous pouvez appliquer un transformateur de résultat (bien que certains problèmes de pagination et de résultat transformateur ):

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

le em.getDelegate () est un hack qui ne fonctionne que si vous utilisez la veille prolongée.

  

Peut-être plus important encore, y a-t-il un   moyen de tirer dans tous les objets enfants, pas   Quelle est la profondeur? Nous avons environ 10-15   classes et pour le serveur nous allons   besoin de tout chargé ... j'étais   éviter d'utiliser FetchType.EAGER comme ça   signifiait sa toujours désireux et en   en particulier les charges frontales Web   tout - mais c'est peut-être le   chemin à parcourir - est-ce ce que vous faites? je   semblent se souvenir de nous essayer avant   et puis obtenir des pages Web très lentes   - mais peut-être que cela signifie que nous devrions utiliser un cache de second niveau?

Si cela vous intéresse toujours, j’ai répondu à une question similaire dans ce sujet comment sérialiser des collections en veille .

Vous utilisez essentiellement un utilitaire appelé bulldozer qui mappe les beans sur un autre haricot, ce qui déclenche tout vos charges paresseuses. Comme vous pouvez l’imaginer, cela fonctionne mieux si toutes les collections sont récupérées avec impatience.

Vous pourriez peut-être faire quelque chose comme ça en utilisant une requête de critères (détachée) et en définissant le mode de récupération. Par exemple,

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();

Cela ne fonctionnerait que pour les relations ManyToOne et pour elles @ManyToOne (fetch = FetchType.EAGER) serait probablement approprié.

Il est découragé de ne pas chercher plus d’une relation OneToMany et / ou cela ne fonctionne pas, comme vous pouvez le lire dans le lien que Jeremy a posté. Il suffit de penser à l’instruction SQL qui serait nécessaire pour effectuer une telle récupération ...

Ce que j’ai fait est de refactoriser le code afin de conserver une mappe d’objets pour les gestionnaires d’entités et chaque fois que je dois actualiser, fermez l’ancien entitymanager de l’objet et ouvrez-en un nouveau. J’ai utilisé la requête ci-dessus sans le fetch , ce qui est trop profond pour répondre à mes besoins - il suffit de faire une jointure simple pour obtenir les lignes de commande - le fetch l’a encore plus en profondeur.

Il n’ya que quelques objets pour lesquels j’ai besoin de cela, environ 20, alors je pense que la surcharge de ressources liée au fait de disposer de 20 entity-managers ouverts n’est pas un problème - bien que les administrateurs de base de données puissent avoir un point de vue différent lorsqu’il est mis en ligne ...

J'ai aussi retravaillé les choses pour que le travail de la base de données se trouve sur le thread principal et dispose du responsable de l'entité.

Chris

Si le problème ne concerne que LazyInitializationExceptions, vous pouvez éviter cela en ajoutant un OpenSessionInViewFilter.
Cela permettra aux objets d'être chargés dans la vue, mais ne réglera pas le problème de vitesse.

     <filter>
        <filter-name>hibernateFilter</filter-name>
        <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top