2008-09-16 24 views
20

W odniesieniu do mojego earlier question, chcę zapewnić wszystkie obiekty podrzędne są ładowane, ponieważ mam wiele wątków, które mogą potrzebować dostępu do danych (i tym samym uniknąć opóźnione ładowanie wyjątków). Rozumiem, że sposobem na to jest użycie słowa kluczowego "pobierz" w zapytaniu (EJB QL). Tak:Hibernate (JPA), jak zrobić chętne zapytanie, ładowanie wszystkich obiektów podrzędnych

select distinct o from Order o left join fetch o.orderLines 

Zakładając model z klasy Order który posiada zestaw OrderLines w nim.

Moje pytanie brzmi, że słowo kluczowe "wyraźny" wydaje się być potrzebne, ponieważ w przeciwnym razie wydaje mi się, że otrzymuję Order dla każdego OrderLine. Czy robię to, co trzeba?

Co ważniejsze, czy istnieje sposób na przyciąganie wszystkich obiektów podrzędnych, bez względu na głębokość? Mamy około 10-15 klas, a dla serwera będziemy potrzebować wszystkiego, co jest załadowane ... Unikam używania FetchType.EAGER, ponieważ oznaczało to, że zawsze jest on chętny, a przede wszystkim front sieciowy ładuje wszystko - ale być może to jest sposób na przejście - to co robisz? Wydaje mi się, że pamiętamy, jak próbowaliśmy tego wcześniej, a potem robiliśmy naprawdę powolne strony - ale może to oznacza, że ​​powinniśmy używać pamięci podręcznej drugiego poziomu?

Odpowiedz

14

Zmiana adnotacji jest złym pomysłem IMO. Ponieważ nie można go zmienić na leniwy w czasie wykonywania. Lepiej, aby wszystko było leniwy, i pobierać w razie potrzeby.

Nie jestem pewien, czy rozumiem Twój problem bez mapowań. Pobranie po lewej stronie powinno być wszystkim, czego potrzebujesz w opisywanym przypadku użycia. Oczywiście otrzymasz z powrotem zamówienie dla każdej linii zamówienia, jeśli linia zamówienia ma zamówienie jako jej rodzic.

8

nie jestem pewien o użyciu sprowadzić słowa kluczowego w EJBQL, może być coraz to mylić z dopiskiem ...

Czy próbowałeś dodając właściwość FetchType do atrybutu związek?

@OneToMany (fetch = FetchType.EAGER)?

Patrz:

http://java.sun.com/javaee/5/docs/api/javax/persistence/FetchType.html http://www.jroller.com/eyallupu/entry/hibernate_exception_simultaneously_fetch_multiple

+0

tak, to jest poprawna odpowiedź –

+6

Facet musi zmienić strategię w czasie wykonywania. – Nullpo

0

To będzie działać tylko dla stosunków ManyToOne i dla nich @ManyToOne (pobranie = FetchType.EAGER) prawdopodobnie właściwe.

Pobranie więcej niż jednej relacji OneToMany jest odradzane i/lub nie działa, jak można przeczytać w zamieszczonym linku Jeremy. Wystarczy pomyśleć o instrukcji SQL, która byłaby potrzebna do zrobienia takiego pobrania ...

0

To, co zrobiłem, to zreorganizować kod, aby zachować mapę obiektów dla menedżerów podmiotów i za każdym razem, gdy potrzebuję odświeżenia, zamknij starego uprawnienia dla obiektu i otwórz nowy. Użyłem powyższej kwerendy bez pobierania pobrać, ponieważ jest zbyt głęboka dla moich potrzeb - po prostu robi zwykły łączenie ciągnie w OrderLines - pobrać powoduje, że idzie jeszcze głębiej.

Jest tylko kilka obiektów, których potrzebuję, około 20, więc uważam, że obciążenie zasobów w przypadku posiadania 20 otwartych użytkowników nie jest problemem - chociaż administratorzy mogą mieć odmienny widok, gdy ten zostanie uruchomiony ...

Przepracowałem również rzeczy, aby db działał w głównym wątku i ma menedżera encji.

Chris

-4

Jeśli problem jest tylko LazyInitializationExceptions, można tego uniknąć poprzez dodanie OpenSessionInViewFilter.
Umożliwi to załadowanie obiektów do widoku, ale nie pomoże w rozwiązaniu problemu z prędkością.

 <filter> 
     <filter-name>hibernateFilter</filter-name> 
     <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 
     </filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>hibernateFilter</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 
+0

Dziękuję, ale ta odpowiedź dotyczy webappów/serwletów, a nie samodzielnej aplikacji, z którą pracuję. –

2

Możliwe, że możesz zrobić coś takiego, używając kwerendy z kryteriami (odklejenie) i ustawiając tryb pobierania. Np.,

Session s = ((HibernateEntityManager) em).getSession().getSessionFactory().openSession(); 
DetachedCriteria dc = DetachedCriteria.forClass(MyEntity.class).add(Expression.idEq(id)); 
dc.setFetchMode("innerTable", FetchMode.JOIN); 
Criteria c = dc.getExecutableCriteria(s); 
MyEntity a = (MyEntity)c.uniqueResult(); 
+0

Dzięki, ale problem polega na tym, że chcę używać utrwalonych obiektów poza głównym wątkiem będącym własnością EM, aby uzyskać przejściowe dane o bieżącym stanie rzeczy. Więc nie mogę użyć głównego EM, ale chcę również tych samych obiektów :( –

3

Czy próbowałeś używać transformatora wyników? Jeśli stosować kryteria zapytań, można zastosować transformator wynik (choć there are some problems with pagination and result transformer):

Criteria c = ((Session)em.getDelegate()).createCriteria(Order.class); 
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
c.list(); 

em.getDelegate() jest hack który działa tylko wtedy, gdy używasz hibernacji.

Być może ważniejsze, jest tam sposób wyciągnąć we wszystkich obiektów podrzędnych, bez względu na to jak głęboko ? Mamy około 10-15 klas i dla serwera będziemy trzeba wszystko ładowane ... Byłem unikanie korzystania FetchType.EAGER jak oznaczało jej zawsze chętny iw poszczególnych końcowych ładunku przedniej internetowej wszystko - ale być może to jest droga do wyjścia - czy to właśnie robisz? I wydaje się pamiętać, że próbujemy tego przed , a następnie dostajemy naprawdę powolne strony - ale może to oznacza, że ​​powinniśmy używać pamięci podręcznej drugiego poziomu?

Jeśli nadal jesteś zainteresowany, odpowiedziałem na podobne pytanie w tym wątku: how to serialize hibernate collections.

Zasadniczo używa się narzędzia o nazwie dozer, które odwzorowuje fasolę na inne ziarna, i w ten sposób uruchamia wszystkie swoje leniwe obciążenia. Jak można sobie wyobrazić, działa to lepiej, jeśli wszystkie zbiory są chętnie pobierane.

Powiązane problemy