Domanda

Esiste un modo per modificare il tipo di recupero JPA su un singolo metodo senza modificare l'oggetto entità?

Ho un livello ORM condiviso costituito da classi di entità JPA. Questo livello ORM è accessibile da due livelli DAO. Un DAO ha bisogno di recupero pigro, come è per la mia applicazione web, l'altro ha bisogno di recupero desideroso, poiché ho bisogno che sia thread-safe.

Ecco un metodo di esempio dal mio thread sicuro DAO,

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

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

Come potrei fare in modo che questo metodo (o l'intera classe) utilizzi il recupero desideroso?

È stato utile?

Soluzione

Suppongo che le associazioni delle tue entità (@OneToOne, @OneToMany, @ManyToOne) siano pigre fechted (FetchType.Lazy)

Quindi posso pensare a due modi:

A. scrivere due query jpa una che recupera l'associazione del pigro (questo è il modo predefinito per l'ibernazione) e una seconda query che esplicita impaziente caricamento dell'associazione (vedi " fetch " parola chiave in query).

        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. usa Hibernate.initialize (entità) per forzare il caricamento desideroso di relazioni pigre di un'entità dopo averla recuperata (ad es. tramite finder ...)

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

Altri suggerimenti

In JPA la modalità di recupero è specificata su ciascun attributo di persistenza, tramite un'annotazione o in un file di mapping xml.

Quindi un modo agnostico del fornitore JPA per raggiungere il tuo obiettivo è avere un file di mappatura separato per ogni livello DAO. Sfortunatamente ciò richiederà una PersistenceUnit separata per ogni file di mappatura, ma puoi almeno condividere le stesse classi di entità e la stessa query JPQL.

Seguono gli scheletri di codice.

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>

Quindi si tratta solo di creare un EntityManagerFactory per l'unità di persistenza appropriata nei livelli DAO.

In realtà non sono necessari due file di mappatura, è possibile specificare LAZY o EAGER come annotazione nell'entità e quindi specificare il contrario in un file di mappatura xml (tuttavia si vorranno comunque due unità di persistenza).

Potrebbe essere un po 'più di codice della soluzione Hibernate sopra, ma l'applicazione dovrebbe essere portabile da altri fornitori di JPA.

A parte questo, OpenJPA fornisce funzionalità simili alla soluzione Hibernate sopra usando FetchGroups (un concetto preso in prestito da JDO).

Un ultimo avvertimento, FetchType.LAZY è un suggerimento in JPA, il provider può caricare le righe avidamente se necessario.

Aggiornato per richiesta.

Considera un'entità come questa:

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

In quel caso avresti ancora bisogno di due unità di persistenza, ma ti serviranno solo orm-lazy.xml. Ho cambiato il nome del campo per riflettere uno scenario più realistico (solo le raccolte e i BLOB utilizzano FetchType.LAZY per impostazione predefinita). Quindi l'orm-lazy.xml risultante potrebbe apparire così:

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

E persistence.xml sarà simile a questo:

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

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

Poiché nessuno ha menzionato OpenJPA, inserirò una risposta qui.

In OpenJPA, le raccolte e i campi configurati in precedenza pigri possono essere caricati con impazienza come di seguito

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

Riferimento: http: //openjpa.apache.org/builds/1.0.3/apache-openjpa-1.0.3/docs/manual/ref_guide_fetch.html

In JPA2 utilizzo EntityGraphs , che ti consente di definire quali entità correlate desideri recuperare:

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

Crea un NamedQuery come hai fatto in precedenza e allega un suggerimento con la chiave javax.persistence.loadgraph o javax.persistence.fetchgraph . Recupererà le entità correlate definite nel grafico.

Puoi trovare i dettagli della differenza tra " loadgraph " e " fetchgraph " qui: Qual è la differenza tra il grafico FETCH e LOAD for Entity di JPA?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top