+ Antworten
Ergebnis 1 bis 4 von 4

Thema: "Paging" bei OneToMany

  1. #1
    User byte Themenstarter

    Registriert seit
    31.07.2013
    Fachbeiträge
    15
    Genannt
    0 Post(s)
    Hallo zusammen,

    ich versuche gerade Hibernate zu verstehen. Die Standardfälle für OneToMany habe ich schon verstanden. Allerdings habe ich eine Anforderung, bei der ich überhaupt nicht weiß, ob bzw. wie man das mit Hibernate umsetzt.

    Es geht um eine OneToMany-Beziehung, in der es eine große Anzahl von Kind-Objekten gibt (im Extremfall hoher 5-stellige Anzahl). Über eine ReST-API soll ein "Paging" implementiert werden, d.h. der Vater und ein kleiner Teil seiner Kinder sollen zurückgegeben werden. Wie holt man die Daten aus der Datenbank, ohne direkt alle Kinder im Speicher zu haben?

    Beispiel: Vater hat viele Kinder verschiedenen Alters. Wie kriege ich den Vater mit den beiden ältesten Kindern?

    Ich könnte mir vorstellen, dass das über JPQL geht?!? Aber das verstehe ich noch nicht genau bzw. habe ich noch nicht zum Laufen gebracht. Ich bitte um Unterstützung

    Gibt es sonst etwas zu beachten beim Umgang mit sehr vielen Kind-Objekten?

    Hier mal ein konkretes Beispiel

    Main.java
    Java Code:
    1. import javax.persistence.EntityManager;
    2. import javax.persistence.EntityManagerFactory;
    3. import javax.persistence.Persistence;
    4.  
    5. public class Main {
    6.     private static final EntityManagerFactory entityManagerFactory;
    7.     static {
    8.         try {
    9.             entityManagerFactory = Persistence
    10.                     .createEntityManagerFactory("test");
    11.  
    12.         } catch (Throwable ex) {
    13.             System.err.println("Initial SessionFactory creation failed." + ex);
    14.             throw new ExceptionInInitializerError(ex);
    15.         }
    16.     }
    17.  
    18.     public static void main(String[] args) {
    19.         EntityManager em = getEntityManager();
    20.         try {
    21.  
    22.             Child child1 = new Child("A", 11);
    23.             Child child2 = new Child("B", 12);
    24.             Child child3 = new Child("C", 13);
    25.             Child child4 = new Child("D", 14);
    26.             Child child5 = new Child("E", 15);
    27.             Father father = new Father("Father", child1, child2, child3,
    28.                     child4, child5);
    29.             persistFather(em, father);
    30.             Father persistedFather = findFather(em, father.getId());
    31.             printFather(persistedFather);
    32.         } finally {
    33.             em.close();
    34.         }
    35.     }
    36.  
    37.     private static Father findFather(EntityManager em, long id) {
    38.         Father fatherFound = null;
    39.         try {
    40.             em.getTransaction().begin();
    41.             fatherFound = em.find(Father.class, id);
    42.             em.getTransaction().commit();
    43.         } catch (Exception e) {
    44.             em.getTransaction().rollback();
    45.         }
    46.         return fatherFound;
    47.     }
    48.  
    49.     private static void persistFather(EntityManager em, Father father) {
    50.         try {
    51.             em.getTransaction().begin();
    52.             em.persist(father);
    53.             em.getTransaction().commit();
    54.         } catch (Exception e) {
    55.             em.getTransaction().rollback();
    56.         }
    57.     }
    58.  
    59.     private static void printFather(Father fatherFound) {
    60.         System.out.println("Father " + fatherFound.getFirstName() + " has "
    61.                 + fatherFound.getChildren().size() + " sons");
    62.         for (Child child : fatherFound.getChildren()) {
    63.             System.out.println("- " + child.getFirstName() + ", "
    64.                     + child.getAge() + " years old");
    65.         }
    66.     }
    67.  
    68.     public static EntityManager getEntityManager() {
    69.         return entityManagerFactory.createEntityManager();
    70.     }
    71. }

    Father.java

    Java Code:
    1. import java.util.Collection;
    2. import java.util.LinkedList;
    3.  
    4. import javax.persistence.CascadeType;
    5. import javax.persistence.Entity;
    6. import javax.persistence.FetchType;
    7. import javax.persistence.GeneratedValue;
    8. import javax.persistence.Id;
    9. import javax.persistence.JoinColumn;
    10. import javax.persistence.OneToMany;
    11.  
    12. public class Father {
    13.     @Id
    14.     @GeneratedValue
    15.     private long id;
    16.  
    17.     private String firstName;
    18.  
    19.     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    20.     @JoinColumn(name = "father_id_fk")
    21.     private Collection<Child> children;
    22.  
    23.     public Father() {
    24.         children = new LinkedList<>();
    25.     }
    26.  
    27.     public Father(String firstName, Child... children) {
    28.         this();
    29.         this.firstName = firstName;
    30.         for (Child child : children) {
    31.             this.children.add(child);
    32.         }
    33.     }
    34.  
    35.     public long getId() {
    36.         return id;
    37.     }
    38.  
    39.     public void setId(long id) {
    40.         this.id = id;
    41.     }
    42.  
    43.     public String getFirstName() {
    44.         return firstName;
    45.     }
    46.  
    47.     public void setFirstName(String firstName) {
    48.         this.firstName = firstName;
    49.     }
    50.  
    51.     public Collection<Child> getChildren() {
    52.         return children;
    53.     }
    54.  
    55.     public void setChildren(Collection<Child> children) {
    56.         this.children = children;
    57.     }
    58.  
    59. }

    Child.java
    Java Code:
    1. import javax.persistence.Entity;
    2. import javax.persistence.GeneratedValue;
    3. import javax.persistence.Id;
    4.  
    5. public class Child {
    6.     @Id
    7.     @GeneratedValue
    8.     private long id;
    9.  
    10.     private String firstName;
    11.  
    12.     private int age;
    13.  
    14.     public Child(String firstName, int age) {
    15.         this.firstName = firstName;
    16.         this.age = age;
    17.     }
    18.  
    19.     public long getId() {
    20.         return id;
    21.     }
    22.  
    23.     public void setId(long id) {
    24.         this.id = id;
    25.     }
    26.  
    27.     public String getFirstName() {
    28.         return firstName;
    29.     }
    30.  
    31.     public void setFirstName(String firstName) {
    32.         this.firstName = firstName;
    33.     }
    34.  
    35.     public int getAge() {
    36.         return age;
    37.     }
    38.  
    39.     public void setAge(int age) {
    40.         this.age = age;
    41.     }
    42. }

    persistence.xml
    XML Code:
    1. <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    2.     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    3.     version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    4.     <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
    5.         <properties>
    6.             <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
    7.             <property name="javax.persistence.jdbc.url"
    8.                 value="jdbc:postgresql://localhost:5432/hibernatetest" />
    9.             <property name="javax.persistence.jdbc.user" value="user" />
    10.             <property name="javax.persistence.jdbc.password" value="password" />
    11.             <property name="hibernate.hbm2ddl.auto" value="create" />
    12.             <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
    13.         </properties>
    14.     </persistence-unit>
    15. </persistence>

  2. #2
    Global Moderator Viertel Gigabyte Avatar von SlaterB
    Registriert seit
    06.08.2008
    Fachbeiträge
    2.710
    Genannt
    286 Post(s)
    mit dem Mapping dürfte das nichts zu tun haben, außer dem Punkt per Lazy Loading die Children nur bei Bedarf dazuzuladen
    https://jaxenter.de/was-du-spater-ka...n-jpa-2-1-2375
    (nur mal ein Link, schreibt eigentlich mehr über Eager, sofort dazu laden.., aber Suchanfrage dürfte klar sein, falls Thema nicht bereits klar)

    wobei, vielleicht gibt es auch noch die Möglichkeit, die gemappten Objekte zu sortieren:
    One To Many With Order By Setting : One To Many Mapping*«*JPA*«*Java Tutorial
    dann wäre in Kombination womöglich etwas erreicht..

    Sortierung geht aber nur einmal, andere Wünsche dann ausgeschlossen

    ---

    Query also,
    dann ist die Frage allgemein, auch SQL, genausogut 'wie die beiden höchsten Einträge einer Tabelle oder einer Berechnung finden?'

    SQL Code:
    1. (select count(*) from Table b where b.xy <= a.xy) >= (select count(*) from Table ) -1
    scheint zu gehen,
    Achtung: wenn 3 oder mehr die höchste gleiche Anzahl haben, dann kommen auch 3 oder mehr

    edit:
    SQL Code:
    1. (select count(*) from Table b where b.xy >= a.xy) <= 2
    sieht eleganter aus, liefert aber bei 3 gleichen nix, hmm.., höhere Grenze ist nie sicher außer wieder Tabellengröße,
    wenn garantiert unterschiedliche Werte, weil z.B. nach Id statt Alter, dann könnte man es wagen
    Geändert von SlaterB (09.04.2015 um 18:48 Uhr)
    Hansa wird Meister

  3. #3
    User byte Themenstarter

    Registriert seit
    31.07.2013
    Fachbeiträge
    15
    Genannt
    0 Post(s)
    Danke für die Links. Das hat mir zumindest mal bestätigt, dass ich nicht komplett auf dem Holzweg bin. Der erste Link beschreibt das Problem ziemlich gut. Es ist beruhigend zu sehen, dass man nicht alleine ist

    Der Unterschied zwischen Lazy-Loading und Eager ist mir bekannt. Auch, dass standardmäßig immer alle" bzw. "irgendwann alle" Children geladen werden. Dann hört es aber schon fast auf mit meinen Kenntnissen über JPA/Hibernate. Das fehlende Verständnis über ORM-Frameworks im Vergleich zu JDBC ist auch mein (übergeordnetes) Hauptproblem. Ich habe das Gefühl, dass man bei ORM-Frameworks komplett anders denken muss.

    Das "One To Many With Order By Setting" muss ich mal näher anschauen. Die feste Sortierung scheint mir im ersten Moment unpassend. Muss aber die Use-Cases nochmal anschauen. Wenn ich dann mit setFirstResult/setMaxResult die Anzahl der Datensätze einschränke, bezieht sich das dann auf die Väter? Oder auf die Kinder? Oder auf die Anzahl der Zeilen, die durch den JOIN entstehen? Das habe ich definitiv noch nicht verstanden.

    Die EntityGraphs klangen im ersten Moment sehr interessant. Muss ich mir definitiv mal anschauen, ob/wie man da Einschränkungen machen kann.

    Mit "normalem" SQL bin ich ziemlich fit. Ich glaube aber, dass da zu spezifische Statements notwendig sind, die nicht in einen generischen Persistence-Service passen. Da scheint mir JPQL und namedQueries eher geeignet.

  4. #4
    Global Moderator Viertel Gigabyte Avatar von SlaterB
    Registriert seit
    06.08.2008
    Fachbeiträge
    2.710
    Genannt
    286 Post(s)
    JPQL bietet sich natürlich an, nur der Einfachheit halber von SQL gesprochen, Querys sind dieselben,

    Queries schlicht zu sortieren und setFirstResult/setMaxResult darauf bzw. Iterator und Abbruch ist natürlich noch schlauer dabei,
    Wirkung bei individuellen Queries ist einfach: bezieht sich genau auf die Ergebnisse,

    falls unklar ist was an Ergebnissen der Query bei einem Join usw. herauskommt, dann das vor Einsatz von solchen Zusätzen testen..

    ---

    so wie du setFirstResult/setMaxResult in einem Zug bei "One To Many With Order By Setting" nennst kann ich nicht unbedingt folgen,
    aber will mal vorsichtshalber nicht ausschließen dass das irgendwas sinnvolles ist

    die Links waren übrigens wirklich nur auf die Schnelle mit einfachen Suchen 'OneToMany Lazy Loading' usw. geholt, ohne dass ich sie besonders empfehlen kann,
    brauchst darauf nicht speziell zu bauen, ist alles und anderes leicht zu finden
    Hansa wird Meister

+ Antworten Thema als "gelöst" markieren

Direkt antworten Direkt antworten

Welche Farbe hat im Allgemeinen das Blut von Säugetieren?

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Ähnliche Themen

  1. Optimistic Locking OneToMany Bidirectional
    Von pl4gu33 im Forum Datenbankprogrammierung
    Antworten: 3
    Letzter Beitrag: 05.05.2014, 20:41
  2. Antworten: 6
    Letzter Beitrag: 27.10.2013, 19:36
  3. Antworten: 1
    Letzter Beitrag: 03.10.2013, 09:15
  4. OneToMany undirektional
    Von SirWayne im Forum APIs & Frameworks
    Antworten: 11
    Letzter Beitrag: 27.06.2009, 16:01
  5. "Auch Skype von angeblicher "Firefox-Lücke" betroffen"
    Von L-ectron-X im Forum Sicherheit
    Antworten: 0
    Letzter Beitrag: 31.07.2007, 20:09

Berechtigungen

  • Neue Themen erstellen: Ja
  • Themen beantworten: Ja
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •