-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: [Solved] Iterator-Version von findAll
PostPosted: Sat Aug 23, 2008 1:18 pm 
Beginner
Beginner

Joined: Thu Jul 24, 2008 3:33 am
Posts: 20
Hallo!

Ich verwende DAO's nach dem Kochrezept auf dieser Seite (siehe Generic Data Access Objects).
Ich habe daher auch die Methode "findAll", die alle Zeilen der Tabelle einliest und als Liste zurückgibt:


Code:
    @SuppressWarnings("unchecked")
    public List<T> findAll() {
        return findByCriteria();
    }

    @SuppressWarnings("unchecked")
    protected List<T> findByCriteria(Criterion... criterion) {
        Criteria crit = getSession().createCriteria(getPersistentClass());
        for (Criterion c : criterion) {
            crit.add(c);
        }
        return crit.list();
   }


Jetzt habe ich aber eine grosse Tabelle und möchte diese nicht sofort einlesen, sondern Element- oder Page-weise. Beim Verfolgen einer Referenz macht hibernate dies automatisch lazy, bei einer Query könnte ich iterate() anstatt list() verwenden, aber was tue ich hier?

scroll und ScrollableResults gefällt mir irgendwie nicht, denn ich will
- wie bei findAll Datenobjekte zurückhaben
- keine Hibernate-Spezialitäten in meiner Schnittstelle haben

Am liebsten wäre mir ein Iterator. Wahrscheinlich steh ich nur im Wald, kann mir jemand einen Schubs geben?
Danke, Christian


Last edited by ChrLipp on Mon Jun 29, 2009 10:41 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 01, 2008 7:25 am 
Beginner
Beginner

Joined: Thu Jul 24, 2008 3:33 am
Posts: 20
Es gibt zwei Varianten, Page-weisen Zugriff oder Zugriff über Cursor. In diesem Post möchte ich den Page-weisen Zugriff beschreiben.

Die API-Funktionen werden im FAQ erklärt, siehe I want to retrieve query results, one page at a time. Die zugehörigen Befehle sind Criteria.setMaxResults() und Criteria.setFirstResult() und führen zu SELECT's von
Code:
SELECT X
FROM Y
LIMIT ?
wenn nur MaxResult gesetzt ist oder FirstResult 0 ist bzw.
Code:
SELECT X
FROM Y
LIMIT ? OFFSET ?
wenn beide Werte gesetzt sind.

Mein GenericDaoHibernateImpl habe ich wie folgt angepasst:
Code:
    /**
     * Erzeugt ein Criteria und initialisiert es mit den übergebenen Criterion's
     * Dieses kann dann zur direkten Suche benutzt werden:<br>
     * <code>createCriteria().list();
     * </code><br>
     * oder mit zusätzlichen Aufrufen weiter konfiguriert werden.
     * @param criterion Liste der Criterion's
     * @return ein initialisiertes Criteria-Objekt
     */
    protected Criteria createCriteria(Criterion... criterion)
    {
        Criteria crit = sessionFactory.getCurrentSession().createCriteria(type);
        for (Criterion c : criterion)
        {
            crit.add(c);
        }
       
        return crit;
    }

    /**
     * Ermittelt alle Objekte.
     * @return   Liste der gefundenen Objekte.
     */
    @SuppressWarnings("unchecked")
    public List<T> findAll()
    {
        return createCriteria().list();
    }

    /**
     * Adapter, um ein Criteria in ein PageIterable einzupacken. Damit kann mit foreach über das
     * Resultset iteriert werden.
     * Use this inside subclasses as a convenience method.
     * @param pageSize Anzahl der maximal zurückgegebenen Sätze pro Aufruf.
     * @param pageNumber 0-basierte Nummer der Page.
     */
    protected Iterable<T> findByCriteriaWithPaging(int pageSize, Criterion... criterion)
    {
        // Criteria erzeugen
        Criteria crit = createCriteria(criterion);
       
        // und in ein PageIterable einpacken
        return new PageIterable(crit, pageSize);
    }
   
    /**
     * Adapter, um Java5 for-each nutzen zu können.
     * @author clipp
     */
    private class PageIterable implements Iterable<T>
    {
        /**
         * Criteria, mit dem gesucht wird.
         */
        private Criteria crit;
       
        /**
         * Grösse einer Seite, die gefetcht wird.
         */
        private int pageSize;

        /**
         * ctor.
         * @param crit
         * @param pageSize
         */
        PageIterable(Criteria crit, int pageSize)
        {
            // Übergabe speichern
            this.crit = crit;
            this.pageSize = pageSize;
        }
       
        public Iterator<T> iterator()
        {
            return new PageIterator(crit, pageSize);
        }
    };
   
    /**
     * Iteriert Page-weise über die Abfrage, die durch ein Criteria definiert ist. 
     * @todo: Folgende Fälle sind zu testen:
     * - leere Tabelle
     * - genau teilbar
     * - mit Rest teilbar, mehr als eine Page
     * - mit Rest teilbar, eine Page
     * @author clipp
     */
    private class PageIterator implements Iterator<T>
    {
        /**
         * Criteria, mit dem gesucht wird.
         */
        private Criteria crit;
       
        /**
         * Grösse einer Seite, die gefetcht wird.
         */
        private int pageSize;
       
        /**
         * Gibt an, welche Page geladen werden soll.
         */
        private int pageNumber = 0;
       
        /**
         * Gibt an, ob eine weitere Page vorhanden ist.
         */
        private boolean hasNextPage = true;
       
        /**
         * Iterator für eine einzelne Page.
         */
        private Iterator<T> iteratorForSinglePage;
       
        /**
         * ctor.
         * @param crit            Criteria, mit dem gesucht wird
         * @param pageSize        Grösse der Page
         */
        public PageIterator(Criteria crit, int pageSize)
        {
            // Übergabe speichern
            this.crit = crit;
            this.pageSize = pageSize;
           
            // Grösse der Page setzen
            crit.setMaxResults(pageSize);
        }
       
        /**
         * Gibt an, ob eine weitere Iteration möglich ist.
         * @return true wenn eine weitere Iteration möglich ist.
         */
        @Override
        public boolean hasNext()
        {
            // wurde der Iterator noch nicht erzeugt, ist die erste Page zu laden
            if (iteratorForSinglePage == null)
            {
                nextPage();
               
                // Iterator der Liste übernimmt restliche Behandlung,
                // inkl. der NoSuchElementException
                return iteratorForSinglePage.hasNext();
            }
           
            // ansonsten prüfen, ob der Iterator hasNext liefern kann
            if (iteratorForSinglePage.hasNext())
            {
                return true;
            }
           
            // wenn nicht, ist die nächste Page zu laden und die Lieferung wieder zu delegieren
            if (hasNextPage)
            {
                nextPage();
                return iteratorForSinglePage.hasNext();
            }
            else
            {
                return false;
            }
        }
       
        /**
         * Setzt den internen Iterator auf die Datensätze der nächsten Page.
         */
        @SuppressWarnings("unchecked")
        private void nextPage()
        {
            // Beginn des ersten Results setzen
            crit.setFirstResult(pageNumber * pageSize);
           
            // Page weiterschalten
            ++pageNumber;
           
            // Berechnen, ob noch weitere Pages vorhanden sind
            List<T> result = crit.list();
            hasNextPage = (result.size() == pageSize);
           
            // Iterator setzen
            iteratorForSinglePage = result.iterator();
        }
       
        /**
         * Returns the next element in the iteration.
         * @exception NoSuchElementException iteration has no more elements.
         */
        @Override
        public T next()
        {
            // wurde der Iterator noch nicht erzeugt, ist die erste Page zu laden
            if (iteratorForSinglePage == null)
            {
                nextPage();
               
                // Iterator der Liste übernimmt restliche Behandlung,
                // inkl. der NoSuchElementException
                return iteratorForSinglePage.next();
            }
           
            // ansonsten prüfen, ob der Iterator next liefern kann
            if (iteratorForSinglePage.hasNext())
            {
                return iteratorForSinglePage.next();
            }

            // wenn nicht, ist die nächste Page zu laden und die Lieferung wieder zu delegieren
            // inkl. der NoSuchElementException
            nextPage();
            return iteratorForSinglePage.next();
        }
       
        @Override
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}


Die Funktion findByCriteria wurde gelöscht. Als Beispiel nun eine spezifische Funktion in einem DAO:
Code:
    public Iterable<Vorgang> findAllWithPaging(int pageSize)
    {
        return findByCriteriaWithPaging(pageSize);
    }


Nun kann ich folgenden Code schreiben:
Code:
    // Iteriere über alle Vorgänge
    for (Vorgang vorgang : vorgangDao.findAllWithPaging(100))
    {
        ...
    }


und alle 100 Einträge wird ein SELECT gegen die Datenbank geschickt. Nicht schlecht, oder?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.