Spring LazyLoading Problem in den Griff bekommen?

Diskutiere LazyLoading Problem in den Griff bekommen? im Application Tier Forum; Hi, ich habe ein Lazy Loading Problem. Bisher habe ich es mit fetchType=EAGER umgangen, aber das soll keine Dauerlösung sein. Hier ein...

  1. membersound
    membersound Neues Mitglied
    Hi,

    ich habe ein Lazy Loading Problem. Bisher habe ich es mit fetchType=EAGER umgangen, aber das soll keine Dauerlösung sein.
    Hier ein konstrutiertes Example. Es macht nicht sonderlich viel Sinn, zeigt aber mein Problem:
    Eine Company hat mehrere Personen. Personen sind über Komposition @OneToMany in der Company enthalten.

    Wenn ich auf die Personenliste aus JSF zugreife, bekomme ich diese Exception:
    Code (Java):
    Schwerwiegend [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-4) javax.el.ELException: /tablePersons.xhtml @31,76 value=" #{calculator.getPersonCount(_var)}":
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: business.domain.Company.personList, no session or session was closed

    tablePersons.xhtml:
    Code (Java):
    <p:dataTable var="_var" value="#{facade.persons}">
    <p:column>
    <h:outputText value="#{calculator.getPersonCount(_var)}" />

    Die Backing Facaden:
    Code (Java):
    @Named
    @RequestScoped
    class Facade() {
        @Inject
        Dao dao;

        List<Company> companies;

        @PostConstruct
        init() {
            companies = Dao.findByNamedQuery("Companies.ALL");
        }
    }


    @Named
    @RequestScoped
    class Calculator {
        int getPersonCount(Company c) {
            return c.getPersonList().size(); //EX
        }
    }

     
    CRUD Service:
    Code (Java):
    @Stateless
    @Transactional
    class Dao() {
        @PersistenceContext
        private EntityManager em;

        //CRUD
    }
    Entity:
    Code (Java):
    @Entity
    @NamedQueries( {
        @NamedQuery(name = Company.ALL",
                    query = "
    SELECT c FROM Company c")
    })
    class Company {
        @OneToMany(cascade = CascadeType.ALL)  // fetch=FetchType.EAGER <-damit funktioniert alles problemlos
        List<Person> personList = new LinkedList<Person>();
    }

    Ich habe bereits den OpenEntityManager für Spring configuriert:

    web.xml:
    [XML] <filter>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <filter-class>
    org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
    <param-name>entityManagerFactoryBeanName</param-name>
    <param-value>entityManagerFactory</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    [/XML]

    Dennoch funktioniert es nicht.
    Danke für jede hilfreiche Idee!
     
    Zuletzt bearbeitet: 3. März 2012
  2. Vielleicht hilft dir das kostenlose Training weiter --> (hier klicken)
  3. JimPanse
    JimPanse Neues Mitglied
    JOIN FETCH verwenden bzw. mit setFirstResult + setMaxResult die Ergebnisse Menge einschränken. Außerdem macht es ja eher
    Sinn die Personen liste eines Unternehmens erst bei Auswahl eines Unternehmens zu laden und nicht alle Unternehmen + deren Personenliste.
     
  4. membersound
    membersound Neues Mitglied
    Achso, hab ich ganz vergessen:
    Die Exception tritt eben genau dann auf, wenn ich die Zeile markiere und daraufhin der Zugriff auf die personList der markierten Company stattfindet.

    Die Ergebnismenge einzuschränken ist (momentan) noch nicht nötig. Will halt erstmal nur erreichen, dass beim Markieren der Company die Persons nachgeladen werden. Damit die Company Tabelle sich schneller aufbaut.
     
  5. JimPanse
    JimPanse Neues Mitglied
    Ich habe immer noch nicht ganz verstanden was du vor hast. Du willst eine Liste mit Unternehmen + die Anzahl der Personen die für das Unternehmen tätig sind anzeigen - richtig?

    Anstatt das
    Code (Java):

     int getPersonCount(Company c) {
            return c.getPersonList().size(); //EX
        }
     
    1. Möglichkeit: Mit einer weiteren Abfrage
    Code (Java):

     int getPersonCount(Company c) {
            return dao.countPerson(c); // SELECT COUNT(t.*) FROM Person t WHERE t.company=:company
        }
     
    2. Möglichkeit - in Company ein Feld einfügen
    Code (Java):

    public class Company
    {
    private transient long nPerson;

    public Company(Company c, long nPerson){
    this.nPerson = nPerson;
    ...
    }

    //getter & setter
    }

     
    Abfrage
    Code (Java):

    SELECT new Company(t.c,size(t.personList)) FROM Company t
     
     
  6. membersound
    membersound Neues Mitglied
    Ich hab doch oben geschrieben:
    "Hier ein konstrutiertes Example. Es macht nicht sonderlich viel Sinn, zeigt aber mein Problem".

    Ich bin mir durchaus bewusst, dass ich dieses Beispiel hier deutlich einfacher realisieren könnte.


    Es geht mir auch nicht um Companies oder Persons. Sondern nur darum, wie ich ohne LazyLoading Exception eine Kompositions-Liste (wie zB personList) laden kann.

    Denn die Companies-Liste "companies" ist in der Klasse Facade() enthalten.
    Wenn ich eine Tabellenspalte markiere, wird eine dieser Companies an eine andere Klasse (Calculator) übergeben. Dort wird dann auf die personList zugegriffen, was eben besagte LazyLoading Ex wirft.

    Ich suche also nach einer Möglichkeit, dieses Verhalten beizubehalten und trotzdem @OneToMany lazy zu nutzen, also Nachladen bei bedarf (beim markieren).


    Deine 1. Möglichkeit sieht soweit brauchbar aus. Aber, dort muss ich ja dann einen erneuten DB-Zugriff ausführen.
    Ist der Sinn und Zweck von LazyLoading nicht der, dass eben kein erneuter DB Zugriff erfolgen muss?
     
  7. JimPanse
    JimPanse Neues Mitglied
    Nein Lazy loading hat den Sinn Daten erst dann zu laden wenn diese benötigt werden d.h.

    JOIN FETCH

    Code (Java):

    FROM Company c JOIN FETCH c.personList WHERE c.id=:id
     
    oder
    Code (Java):

    SELECT DISTINCT c FROM Company c JOIN FETCH c.personList
     
     
  8. membersound
    membersound Neues Mitglied
    Ja schon klar, aber man muss das doch irgendwie an Hibernate oder Spring delegieren können? Ohne immer selbst unzählige SQL fetches zu schreiben.

    /edit: habe gerade mal den em mit extended annotiert. Damit würde es auch funktionieren, dh keine ex mehr werfen.
    @PersistenceContext(type=PersistenceContextType.EXTENDED)
     
    Zuletzt bearbeitet: 3. März 2012
  9. JanHH
    JanHH Mitglied
    Also für mich sieht das ganz simpel danach aus dass Du auf eine @OneToMany-Collection einer Entity zugreifen willst, welche sich zu dem Zeitpunkt nicht im Persistenzkontext befindet. Also bei Deiner Funktion dann

    Code (Java):

     int getPersonCount(Company c) {
       Company c2=entityManager.find(Company.class, c.getId());
       return c2.getPersonList().size(); //EX
     }
     
    wobei Du natürlich da irgendwo den entityManager injecten musst. Lazy Loading geht natürlich nur wenn die Entity im Persistenzkontext ist, aber wenn da mehrere Requests zwischen liegen (wie z.B. bei einer Liste auf einer Webseite wo ein Entity angeklickt wird), dann ist sie detached und dann geht das halt nicht.
     
  10. Schau dir jetzt hier den Kurs an und lerne Java zu programmieren: --> Hier klicken, um mehr zu erfahren (Klick)
Die Seite wird geladen...

LazyLoading Problem in den Griff bekommen? - Ähnliche Themen

JDBC Methodenaufruf Problem
JDBC Methodenaufruf Problem im Forum Java Basics - Anfänger-Themen
Timer Probleme
Timer Probleme im Forum Für Verirrte - Fragen zu JavaScript
LIBGDX Texturen Problem
LIBGDX Texturen Problem im Forum Spiele- und Multimedia-Programmierung
Probleme beim befüllen eines Tableviews
Probleme beim befüllen eines Tableviews im Forum AWT, Swing, JavaFX & SWT
LIBGDX Problem beim resizen des Frames
LIBGDX Problem beim resizen des Frames im Forum Spiele- und Multimedia-Programmierung
Thema: LazyLoading Problem in den Griff bekommen?