Konwersja Entity na wiele DTO

0

Cześć.
Mam projekt w którym zapisuje Userów do bazy, W RESTowym API przyjmuje np. UserDTO, przepuszczam to potem w serwisie przez UserConverter i na wyjściu otrzymując Entity zapisuje to do bazy. Żeby obsłużyć zapytanie o rejestrację użytkownika potrzebuje więc klasę DTO, Entity i konwerter który zamienia w obie strony.
Teraz powiedzmy że chciałbym pobrać użytkownika (np. żeby wyświetlić stronę z ustawieniami użytkownika). Część pól z poprzedniego UserDTO nie jest mi już potrzebna więc jedyne co zauwazam to dodanie kolejnego DTO i następny konwerter.
Ma to w ogóle sens? Za chwile okaże się że mam wiele DTOsów i konwerterów które niewiele się od siebie różnią. Druga sprawa że modyfikując Entity może się okazać że wszystkie te konwertery będę musiał aktualizować...
Jakiś pomysł jak coś takiego sensownie obsługiwać?
Ps. Projekt pisany w Javie ale problem jest raczej ogólny więc język nie ma tu chyba większego znaczenia.

Pozdrawiam

0

Ja dla każdego widoku na froncie mam osobnego dtosa, ale nie muszę już nic mapować z encji - jeśli muszę coś popchać po prostu do klienta, nie updatuje mi to stanu aplikacji to wyciągam z bazy dtosa bezpośrednio przez jakiś query service i wypycham restem. Poczytaj o CQRS i JOOQ.

0
Bambo napisał(a):

Ja dla każdego widoku na froncie mam osobnego dtosa, ale nie muszę już nic mapować z encji - jeśli muszę coś popchać po prostu do klienta, nie updatuje mi to stanu aplikacji to wyciągam z bazy dtosa bezpośrednio przez jakiś query service i wypycham restem. Poczytaj o CQRS i JOOQ.

Okej rzucę okiem.
U mnie problem jest jednak taki że mam hibernate'a (a w niektórych częściach jeszcze eksperymentalnie Spring Data JPA) i to samo w sobie wymusza już posiadanie klas Entity. Robiąc więc zwykłego select'a na wyjściu dostaję np. UserEntity które muszę przekonwertować żeby nie wypychać encji na widok. Czytałem artykuły tego typu:
https://smarterco.de/spring-data-jpa-query-result-to-dto/
z których wynika że można na wyjściu dostać DTO po zwykłym zrobieniu selecta ale takie egzotyczne rozwiązania mnie jakoś nie przekonują bo mam wrażenie że sprawdzają się tylko w prostych przypadkach.

0

Dlatego staram się jpa nie używać :). Możesz też porobić sobie widoki zmaterializowane.

0

No tak, to prawda ale jednak wiele projektów hula na JPA i przypuszczam że do każdego select'a nie robi się widoków i jakoś to działa stąd też moje pytanie czy ma ktoś jakieś sprawdzone rozwiązania na to?

0

Ja sobie chwalę to rozwiązanie które wcześniej podlinkowales, czyli używanie konstrukcji "select new dto(...) from".

0

A masz jakiś ciekawszy sposób niż tworzenie konstruktora ze wszystkimi polami i potem bindowanie to na zapytaniu?
W przypadku kilku pól nawet sobie wyobrażam użycie takie konstruktora natomiast jak mam powiedzmy klasę User, ona ma kilka pól typu imie, nazwisko itp oraz np. AdressDTO, SpecificDataDTO itp to musiałbym w tych wszystkich klasach dodatkowych też robić takie konstruktory i ten zwykły select byłby jakimś kosmicznie nieczytelnym tworem.

0

Może projekcje ?

0
eL napisał(a):

A masz jakiś ciekawszy sposób niż tworzenie konstruktora ze wszystkimi polami i potem bindowanie to na zapytaniu?
W przypadku kilku pól nawet sobie wyobrażam użycie takie konstruktora natomiast jak mam powiedzmy klasę User, ona ma kilka pól typu imie, nazwisko itp oraz np. AdressDTO, SpecificDataDTO itp to musiałbym w tych wszystkich klasach dodatkowych też robić takie konstruktory i ten zwykły select byłby jakimś kosmicznie nieczytelnym tworem.

Jak jest sporo konkretnych kolumn do pobrania to i tak zwykle trzeba je wszystkie wymienić w projekcji, więc dodanie samego wywołania konstruktora w zapytaniu nie wydaje mi się dużym problemem.
W przypadku gdy chcemy stworzyć kilka obiektów, zwykle robię to jak w odpowiedzi tutaj: https://stackoverflow.com/questions/40218903/hibernate-hql-multiple-new-objects
Też mam trochę wątpliwości, czy to jest najlepsze rozwiązanie, ale zwykle wychodziło jako najkrótsze.

W przypadku gdy liczba kolumn do pobrania jest bardzo dużo, to zwykle kończę z widokiem przykrywającym zapytanie i osobnym mappingiem na widok.

0
Bambo napisał(a):

Ja dla każdego widoku na froncie mam osobnego dtosa, ale nie muszę już nic mapować z encji - jeśli muszę coś popchać po prostu do klienta, nie updatuje mi to stanu aplikacji to wyciągam z bazy dtosa bezpośrednio przez jakiś query service i wypycham restem. Poczytaj o CQRS i JOOQ.

Też staram się tak robić, szczególnie kiedy posiada się lomboka, to zrobienie tych dto jest bardzo proste i szybkie.
Jeżeli jakaś encja może posiadać kilka stanów, którym odpowiadają różne dto, to zrobiłbym ich tyle ile trzeba.

0

A dlaczego nie używasz budowniczego? Jak masz lomboka to oznaczasz sobie klasę @Builder i nie musisz robić masy konwerterów, równie dobrze możesz zrobić taką mini fabrykę, gdzie po prostu uzupełniasz pola jakie chcesz. Tylko wtedy niektóre pola mogą przyjść jako 0 dla inta lub null dla obiektów/stringa więc na froncie musiałbyś sprawdzać czy jakiś element nie jest nullem.

0
Aleksander Brzozowski napisał(a):
Bambo napisał(a):

Ja dla każdego widoku na froncie mam osobnego dtosa, ale nie muszę już nic mapować z encji - jeśli muszę coś popchać po prostu do klienta, nie updatuje mi to stanu aplikacji to wyciągam z bazy dtosa bezpośrednio przez jakiś query service i wypycham restem. Poczytaj o CQRS i JOOQ.

Też staram się tak robić, szczególnie kiedy posiada się lomboka, to zrobienie tych dto jest bardzo proste i szybkie.
Jeżeli jakaś encja może posiadać kilka stanów, którym odpowiadają różne dto, to zrobiłbym ich tyle ile trzeba.

Wcześniej myślalem że robienie wielu DTO + konwerter dla każdego z widoków jest głupie bo sporo kodu podobnego powstaje ale z drugiej strony jak czytam że inni tak robią to zaczynam się sam zastanawiać że to w sumie może mieć sens i jest przynajmniej bardziej czytelne niż kombinowanie z jakimś jednym DTO żeby go na kilka widoków użyć.

Mam lomboka i buildera w projekcie i moje konwertery tak budują DTO albo Entity.
Mógłbym pozbyć się konwerterów i tworzyć te obiekty przez buildera w miejscach gdzie to potrzebuje, natomiast niektóre klasy są bardzo rozbudowane więc wolę to zamknąc w konwerterach.

Generalnie z tego co rozumiem to pomijając sposób z JOOQ (bo niestety już mam jpa w projekcie) to zostaje mi to samemu konwertować albo zrobić jakieś projekcje itp. i tak czy inaczej nie ma na to jakiegoś sprytnego wzorca który by pozwolił nie klepać aż tyle kodu a jednocześnie byłby bardzo czytelny.

2

Wydziel grupy pól które się powtarzają.
Np. w UserProfileDTO wydziel sobie atrybut UserDTO user, w którym masz te powtarzające się dane np. username, avatar.

Jeśli chcesz, żeby struktura zserializowanego w JSONie UserProfileDTO była płaska (np. nie chcesz pola user, tylko od razu username, password), to używasz adnotacji @JsonUnwrapped

Potem możesz sobie ten UserDTO tak samo komponować do innych DTO.

0

Okej, dzięki bardzo!
Myślę że konwertery i pomysł @qbns są dla mnie wystarczające. Przy pobieraniu danych z bazy jeśli się okażę że sporo kolumn w danym momencie nie jest potrzebne to żeby nie zaciągać za dużo danych będę po prostu dodawać projekcje albo widoki. Tak czy inaczej myślałem że znajdę jedno konkretne rozwiązanie które będzie uniwersalne dla wszystkich przypadków ale jednak okazuje się że lepiej będzie mixować je w zależności od potrzeb. Dzięki.

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