Hibernate - odtworzenie znullowanych leniwych relacji

0

Mam mały problem: gdy encje przychodzą mi do servera po komunikacji z klientem (czyli po serializacji i deserializacji) mam znullowane niektóre relacje (te co miały lzy loading ustawione)

Znacie może jakiś sprytny sposób aby żeby je odtworzyć ?

Bo jak zrobię EntityManager.merger i w relacji OneToMany będę miał null to mi wywali wszystkie encje z tej relacji.

Można na przykład samemu stworzyć jakoś pusty PersistantBag (który wstawiłbym w miejsce tych null'i) tak żeby Hibernate go zainicjalizował przy mergu ?

0
  1. Nie mozesz ich od razu pobrać przy wyciąganiu z bazy? (nie mówie oczywiście o eager tylko o fetch join przy zapytaniu)
  2. Możesz po prostu "na jana" wyciągnąć sobie te encje z bazy, przypisać do nulli i zrobić merge i powinno banglać. Oczywiście jest to malo wygodne bo dużo ręcznego kombinowania.
0
Shalom napisał(a):
  1. Nie mozesz ich od razu pobrać przy wyciąganiu z bazy? (nie mówie oczywiście o eager tylko o fetch join przy zapytaniu)

Jakim wyciąganiu z bazy ? Chyba nie zrozumiałeś o co mi chodzi - albo ja Ciebie.
Przychodzi do mnie encja z zewnątrz, od klienta, z zmianami. Muszę ją z merge'ować z tą co siedzi w bazie. Nie mogę tego zrobić zanim nie zrobię coś z tymi nullowanymi relacjami.

Shalom napisał(a):
  1. Możesz po prostu "na jana" wyciągnąć sobie te encje z bazy, przypisać do nulli i zrobić merge i powinno banglać. Oczywiście jest to malo wygodne bo dużo ręcznego kombinowania.

No właśnie chyba tak zrobię - tylko się zastanawiałem czy jest jakieś bardziej ogólne rozwiązanie tego problemu.

1

Ad.1. Ja rozumiem o czym piszesz, ale jakoś te dane wysłałeś do klienta do pozmieniania. Jak mu wyślesz bez nulli to i wróci bez nulli ;)
Ad.2. Ja o takim nie słyszałem, ale nie jestem w tej dziedzinie wybitnym ekspertem, może ktoś będzie coś więcej wiedział. @Koziołek @Wibowit @wiciu ? :)

0

Ad.1. Jak nie wyśle z nullami to albo dostanę LazyLodaingException podczas serializacji odpowiedzi do klienta albo będę musiał przez sieć wysłać tysiące niepotrzebnych encji :P
Ad.2. Też nic takiego nie widzę - więc robie se własne narzędzie co mi to trochę zautomatyzuje - już tak czy owak zrobiłem własnego liba do konfiguracji Spring Remoting (RMI i Hessian) przy pomocy dwóch adnotacji w Java Config:
https://bitbucket.org/walczak_it/prodoko-base/src/HEAD/prodoko-remoting/src/main/java/com/prodoko/remoting/?at=master
więc to powinno być małym piwem ;)

0

Alternatywnie można spróbować zmienić "właściciela" relacji na tą drugą stronę (mapped by) i wtedy jak merge napotka nulle to wydaje mi sie że zamiast usuwać uzupełni sobie. Ale to znów nie jest coś co można zastosować zawsze ;)

0

Troche nie czaje problemu chyba.

  1. Jesli wysylasz encje z nullami ktore po wybraniu z bazy o ile dobrze rozumiem sam wstawiasz, to dostajesz takie encje z powrotem i wiadomo, wszystko jest usuwane. Jak zmieniasz encje hibernatowe w jedna strone (po odczycie) to przy zapisie / mergu musisz je zmienc w druga strone (dodac te 'zgubione' kolekcje). Innej rady nie ma.
  2. Mowisz ze klient moze dostac LazyInitializationException czy jak sie to zwie. Ok, ale z Twoimi zmianami moze dostac NPE. Jesli klient nie dostaje NPE to albo nie uzywa tych kolekcji (w zwiazku z czym nie ma problemu - slij lazy kolekcje) albo testuje != null, co jest ogolnie niezgodne z hibernate poniewaz on kolekcje ma zawsze nie-nullowe.

Jak by nie patrzec, to nadbudowales na hb jakies swoje 'rozszerzenie', ktore jest polowicznie zaimplementowane - nulluje kolekcje przy odczycie, ale nie przywraca ich przed zapisem / mergem. Jesli dalej chcesz ciagnac ta strategie, to chyba bys musial zaimplementowac swojego merga - pobrac znowu encje z bazy, 'nalozyc' na nia zmiany klienta (nie nadpisywac kolekcji ktore sam znullowales!) i ta prawdziwa encje mergowac - wtedy lazy kolekcje pozostana lazy.
Pytanie jak zapamietac ktore kolekcje sa lazy a ktore klient naprawde zmienil - nie wiem jak to jest w Twoim kodzie, moze jest to latwe do odgadniecia, moze nie, ale mozna to zrobic tak, ze w momencie gdy nullujesz kolekcje 'zbierasz' info o tym ktore byly lazy i zapisujesz do jakiegos pola transient w tej encji. Gdy ona wraca do ciebie od klienta, przy twojej wlasnej implementacji merga masz to dodatkowe info dostepne.
Ogolnie beznadziejny pomysl z tym nullowaniem. Klient to kto? Czesc twojej aplikacji? To napraw kod i nie korzystaj z lazy kolekcji. Jesli klient to nie twoj kod ktory jest gdziesz na innym serwerze to i tak slanie encji hibernatowych nie jest moim zdaniem szczesliwym pomyslem.

1

Biblioteka ktora umie mapowac beany ktora kiedys ogladalem sie zwie Dozer (chyba). Tam sa jakies konwencje ale mozna mapowac za pomoca xml (a jakze). Wiec jak bys zrobil jakies DTO i slal to zamiast encji hb to jak by wracalo to moglbys wszystkie propertisy znowu zmapowac do nowo wczytanej ale poprawnej encji hb.

0

Tak, też się natknąłem na Dozer'a - ale staram się uniknąć właśnie jakiś mapowań XML oraz samych DTO.

0

Ja osobiście mam złe doświadczenia z traktowaniem obiektów encyjnych jako beanów i DTO. Bo potem są właśnie takie cuda na kiju że nagle ci coś znika z bazy tylko dlatego że miałeś transakcje na poziomie serwisu (więc otwartą sesję) a szykując dane do wysłania pousuwałeś jakieś kolekcje żeby nie wysyłać niepotrzebnych danych ;)
A otwarta sesja = automatyczna synchronizacja obiektu encyjnego z bazą ;]

0

Problem z którym walczysz niedawno na Trójmiejskim JUGu Sławek Sobótka nazwał podejściem "Encja na twarz i pchasz".

Generalnie z moich doświadczeń też powoduje to trochę problemów. Hibernate opakowuje swoje encje w proxy co czasami może doprowadzić do np. nieskończonej rekurencji (ja miałem taki problem przy połączeniu JAX-RSa z HALem). Generalnie dałem sobie spokój z unikaniem DTO i zauważyłem więcej plusów niż minusów.

0

DTO lub obóz alternatywny OpenSessionInView

0

Przy serializacji OpenSessionInView mogło by pomóc ale to mam ogarnięte. Przy deserializacji nic nie da.

DTO trochę śmierdzi bo robi dodatkową hierarchię modelu a u mnie w GUI są dwa bardzo ważne komponenty budowane z retrospecji obiektu modelowego.

Piszę właśnie utilitysa co mi encje wyczyści z macków dowolnego liba JPA i znuluje odpowiednie relacje - w ten sposób stanie się DTO bez zmiany klasy - a potem ten sam lib będzie wiedział, które rzeczy przekopiować do encji jak wróci DTO - czyli nie znuluje mi faktycznych relacji. Mamo to oparte na annotatcjach więc w API po stronie klienta widać kontrakt gdzie nulle oznaczają faktyczne nulle a gdzie stanowią ucięcie grafu obiektów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1