Question

Existe-t-il un moyen de changer le type de récupération JPA sur une seule méthode sans modifier l'objet entité?

J'ai une couche ORM partagée composée de classes d'entités JPA. Cette couche ORM est accessible par deux couches DAO. Un DAO a besoin de chercher paresseux, comme c'est le cas pour mon application Web, l'autre a besoin de chercher rapidement, car j'ai besoin que ça soit threadsafe.

Voici un exemple de méthode tiré de mon DAO threadsafe,

@PersistenceContext(unitName = "PersistenceUnit", type = PersistenceContextType.TRANSACTION)
private EntityManager em;

public ErrorCode findErrorCodeById(short id) {
    return (ErrorCode) em.createNamedQuery("ErrorCode.findById").
            setParameter("id", id).getSingleResult();
}

Comment pourrais-je faire en sorte que cette méthode (ou toute la classe) utilise la récupération désirée?

Était-ce utile?

La solution

Je suppose que vos associations d'entités (@OneToOne, @OneToMany, @ManyToOne) sont fictives (FetchType.Lazy)

Ensuite, je peux penser à deux manières:

A. écrivez deux requêtes jpa, l'une qui va chercher l'association du paresseux (c'est le moyen par défaut pour hibernate) et une seconde, qui force explicitement le chargement de l'association (voir le mot-clé "fetch" dans la requête).

        Query q = HibernateUtil.getSessionFactory().getCurrentSession()
                .createQuery("select c from Category as c" +
                        " left join fetch c.categorizedItems as ci" +
                        " join fetch ci.item as i");


B. utilisez Hibernate.initialize (entité) pour forcer le chargement rapide des relations paresseuses d’une entité après l’avoir récupérée (par exemple, par le biais du viseur ...)

ErrorCode lazyCode = findErrorCodeById(1);
// eager load associations
Hibernate.initialize(lazyCode);

Autres conseils

Dans JPA, le mode de récupération est spécifié pour chaque attribut de persistance, soit par une annotation, soit dans un fichier de mappage xml.

Ainsi, un moyen agnostique pour les fournisseurs JPA d’atteindre votre objectif est d’avoir un fichier de mappage séparé pour chaque couche DAO. Malheureusement, cela nécessitera un PersistenceUnit distinct pour chaque fichier de mappage, mais vous pouvez au moins partager les mêmes classes d'entités et la même requête JPQL.

Les squelettes de code suivent.

persistence.xml:

<persistence>
    <persistence-unit name="dao-eager">
        <mapping-file>orm-eager.xml</mapping-file>
    </persistence-unit>

    <persistence-unit name="dao-lazy">
        <mapping-file>orm-lazy.xml</mapping-file>
    </persistence-unit>
</persistence>

orm-eager.xml:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <basic name="name" fetch="EAGER"/>
        </attributes>
    </entity> 
</entity-mappings>

orm-lazy.xml:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <basic name="name" fetch="LAZY"/>
        </attributes>
    </entity> 
</entity-mappings>

Ensuite, il suffit de créer un EntityManagerFactory pour l'unité de persistance appropriée dans vos couches DAO.

En fait, vous n'avez pas besoin de deux fichiers de mappage, vous pouvez spécifier soit LAZY, soit EAGER en tant qu'annotation dans l'entité, puis le contraire dans un fichier de mappage xml (vous souhaiterez quand même deux unités de persistance).

Peut-être un peu plus de code que la solution Hibernate ci-dessus, mais votre application doit être portable pour les autres fournisseurs JPA.

Soit dit en passant, OpenJPA fournit des fonctionnalités similaires à la solution Hibernate décrite ci-dessus en utilisant FetchGroups (un concept emprunté à JDO).

Un dernier avertissement, FetchType.LAZY est un indice dans JPA, le fournisseur peut charger les lignes avec impatience si nécessaire.

Mis à jour par demande.

Considérons une entité comme celle-ci:

@Entity 
public class ErrorCode { 
    //  . . . 
    @OneToMany(fetch=FetchType.EAGER)  // default fetch is LAZY for Collections
    private Collection myCollection; 
    // . . .
}

Dans ce cas, vous aurez toujours besoin de deux unités de persistance, mais vous aurez uniquement besoin de orm-lazy.xml. J'ai changé le nom du champ pour refléter un scénario plus réaliste (seules les collections et les blobs utilisent FetchType.LAZY par défaut). Ainsi, le fichier orm-lazy.xml obtenu pourrait ressembler à ceci:

<entity-mappings>
    <entity class="ErrorCode">
        <attributes>
            <one-to-many name="myCollection" fetch="LAZY"/>
        </attributes>
    </entity> 
</entity-mappings>

Et persistence.xml ressemblera à ceci:

<persistence>
    <persistence-unit name="dao-eager">
       <!--
          . . .
         -->
    </persistence-unit>

    <persistence-unit name="dao-lazy">
        <!--
           . . . 
          -->
        <mapping-file>orm-lazy.xml</mapping-file>
    </persistence-unit>
</persistence>

Puisque personne n'a mentionné OpenJPA, je vais mettre une réponse ici.

Sous OpenJPA, les collections et les champs configurés précédemment paresseux peuvent être chargés avec impatience comme suit:

    OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
    kem.getFetchPlan().addField(Order.class, "products");
    TypedQuery<Order> query = kem.createQuery(yourQuery, Order.class);

Référence: http: //openjpa.apache.org/builds/1.0.3/apache-openjpa-1.0.3/docs/manual/ref_guide_fetch.html

Dans JPA2 , j'utilise EntityGraphs , qui vous permet de définir les entités associées que vous souhaitez récupérer:

https://docs.oracle.com/javaee/7 /tutorial/persistence-entitygraphs002.htm https://docs.oracle.com/javaee/7/tutorial/ persistence-entitygraphs003.htm

Vous créez une NamedQuery comme vous l'avez fait et vous attachez un indice avec la clé javax.persistence.loadgraph ou javax.persistence.fetchgraph . Il va récupérer les entités liées que vous avez définies dans le graphique.

Vous pouvez trouver les détails de la différence entre " loadgraph " et " fetchgraph " ici: Quelle est la différence entre le graphique FETCH et LOAD for Entity de JPA?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top