2009-06-24 4 views
18

Gibt es eine Möglichkeit, den JPA-Abruftyp für eine einzige Methode zu ändern, ohne das Entitätsobjekt zu bearbeiten?Gibt es eine Möglichkeit, den JPA-Abruftyp für eine Methode zu ändern?

Ich habe eine gemeinsame ORM-Schicht, die aus JPA-Entitätsklassen besteht. Auf diese ORM-Schicht wird von zwei DAO-Schichten zugegriffen. Ein DAO benötigt, wie für meine Web-Anwendung, ein langsames Holen, das andere muss eifrig abgerufen werden, da es threadsicher sein muss. Hier

ist ein beispielhaftes Verfahren von meinem Thread-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(); 
} 

Wie würde ich diese Methode (oder ganz Klasse) eifrig fetching benutzen?

Antwort

15

Ich gehe davon aus, dass Ihr Unternehmen Verbände (@OneToOne, @OneToMany, @ManyToOne) sind fechted faul (FetchType.LAZY)

Dann kann ich zwei Möglichkeiten denken:

A. zwei JPA-Abfrage schreiben eine, die die Verbindung der Lazy (das ist die standardmäßige Art und Weise für den Winterschlaf) und eine zweite Abfrage, die explizites force erigendes Laden der Assoziation (siehe "fetch" Schlüsselwort in der Abfrage) holen.

 
     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. Hibernate.initialize (entity) verwenden eifrig Laden von faulen Beziehungen eines Unternehmens zu erzwingen, nachdem Sie sie abgerufen haben (zB durch finder ...)

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

Danke Klaus, offensichtlich Option B ist der Code, abhängig vom Import von Hibernate gehen machen, was ein Nachteil ist, aber ich Ich werde es versuchen. –

+1

Hallo Nemo, kannst du bitte meine Antwort mit dem grünen Häkchen markieren. ;) – H2000

+0

Ich bin immer noch ein 'Sitzung geschlossen' Problem mit Methode b. –

9

In JPA die Fetch Der Modus wird für jedes Persistenzattribut entweder über eine Annotation oder in einer XML-Zuordnungsdatei angegeben.

Also ein JPA-Anbieter agnostic Weg, um Ihr Ziel zu erreichen ist separate Mapping-Datei für jede DAO-Schicht. Leider erfordert dies eine separate PersistenceUnit für jede Zuordnungsdatei, aber Sie können zumindest die gleichen Entitätsklassen und die gleiche JPQL-Abfrage verwenden.

Code Skelette folgen.

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> 

Dann ist es nur eine Frage der eine EntityManagerFactory Schaffung für die entsprechende Persistenz-Einheit in Ihren DAO-Layern.

Eigentlich brauchen Sie nicht zwei Mapping-Dateien, Sie könnten entweder LAZY oder EAGER als Annotation in der Entity angeben und dann das Gegenteil in einer XML-Mapping-Datei angeben (Sie wollen aber immer noch zwei Persistenz-Einheiten).

Möglicherweise ein wenig mehr Code als die Hibernate-Lösung oben, aber Ihre Anwendung sollte für andere JPA-Anbieter tragbar sein.

Nebenbei bietet OpenJPA eine ähnliche Funktionalität wie die obige Hibernate-Lösung mit FetchGroups (ein Konzept, das von JDO übernommen wurde).

Ein letzter Vorbehalt, FetchType.LAZY ist ein Hinweis in JPA, der Provider kann die Zeilen bei Bedarf geladen werden.

Aktualisiert pro Anfrage.

eine Einheit wie folgt vor:

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

In diesem Fall, dass Sie noch zwei Persistenzeinheiten bräuchten, aber Sie werden nur ORM-lazy.xml benötigen. Ich habe den Feldnamen geändert, um ein realistischeres Szenario darzustellen (nur Sammlungen und Blobs verwenden standardmäßig FetchType.LAZY). So ist die resultierende ORM-lazy.xml könnte wie folgt aussehen:

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

Und persistence.xml wird wie folgt aussehen:

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

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

Mike, können Sie genauer auf "Eigentlich brauchen Sie nicht zwei Mapping-Dateien, können Sie entweder LAZY oder EAGER als eine Annotation in der Entität angeben und dann das Gegenteil in einer XML-Mapping-Datei angeben"? –

+0

Ich habe ein schnelles Beispiel hinzugefügt. Ich hoffe es hilft. – Mike

+0

Wir bearbeiten die XML-Datei, um die Anmerkungen zu ändern, ähnelt der Bearbeitung des Entitätsobjekts. Dies könnte jedoch die beste Option sein, die ich habe. –

0

In JPA2 I EntityGraphs verwenden, die Sie, was zu definieren erlaubt Verwandte Entitäten, die Sie abrufen möchten:

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

Sie erstellen eine NamedQuery wie Sie, und Sie fügen einen Tipp mit Schlüssel javax.persistence.loadgraph oder javax.persistence.fetchgraph. Es ruft die verwandten Entitäten ab, die Sie im Diagramm definiert haben.

Sie können die Details des Unterschiedes zwischen „loadgraph“ und „fetchgraph“ finden Sie hier: What is the diffenece between FETCH and LOAD for Entity graph of JPA?

Verwandte Themen