W swoim projekcie używam JPA.
Doszedłem do zapytania, w którym muszę wykonać operację łączenia na pięciu tabelach. Utworzyłem więc natywne zapytanie, które zwraca pięć pól.
Teraz chcę przekonwertować obiekt wynikowy na klasę POJO Java, która zawiera te same pięć ciągów.
Czy istnieje sposób w JPA na bezpośrednie rzutowanie tego wyniku na listę obiektów POJO?
Doszedłem do następującego rozwiązania ..
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Teraz w resultClass, czy musimy podać klasę, która jest rzeczywistą jednostką JPA? LUB Możemy go przekonwertować na dowolną klasę JAVA POJO, która zawiera te same nazwy kolumn?
Odpowiedzi:
JPA zapewnia,
SqlResultSetMapping
który umożliwia mapowanie wszystkiego, co zwraca z natywnego zapytania, na jednostkęlub klasę niestandardową.EDYCJA JPA 1.0 nie zezwala na mapowanie do klas niebędących jednostkami. Tylko w JPA 2.1 ConstructorResult został dodany do odwzorowania wartości zwracanych w klasie java.
Również w przypadku problemu OP z uzyskaniem licznika powinno wystarczyć zdefiniowanie mapowania zestawu wyników za pomocą pojedynczego
ColumnResult
źródło
ConstructorResult
jako jeden z parametrów,SqlResultSetMapping
który pozwala na użycie pojo ze wszystkimi polami ustawionymi w konstruktorze. Zaktualizuję odpowiedź.Znalazłem kilka rozwiązań tego problemu.
Korzystanie z mapowanych jednostek (JPA 2.0)
Przy użyciu JPA 2.0 nie jest możliwe odwzorowanie natywnego zapytania na POJO, można to zrobić tylko z jednostką.
Na przykład:
Ale w tym przypadku,
Jedi
musi być mapowaną klasą jednostki.Alternatywą pozwalającą uniknąć tutaj niezaznaczonego ostrzeżenia byłoby użycie nazwanego zapytania natywnego. Więc jeśli zadeklarujemy natywne zapytanie w encji
Następnie możemy po prostu zrobić:
Jest to bezpieczniejsze, ale nadal jesteśmy ograniczeni do używania zmapowanego obiektu.
Ręczne mapowanie
Rozwiązaniem, które trochę eksperymentowałem (przed pojawieniem się JPA 2.1) było mapowanie w konstruktorze POJO z użyciem odrobiny odbicia.
Ta metoda zasadniczo pobiera tablicę krotek (zwracaną przez natywne zapytania) i mapuje ją na podaną klasę POJO, szukając konstruktora, który ma taką samą liczbę pól i jest tego samego typu.
Następnie możemy skorzystać z wygodnych metod, takich jak:
I możemy po prostu użyć tej techniki w następujący sposób:
JPA 2.1 z @SqlResultSetMapping
Wraz z pojawieniem się JPA 2.1, możemy użyć adnotacji @SqlResultSetMapping, aby rozwiązać problem.
Musimy zadeklarować mapowanie zestawu wyników gdzieś w encji:
A potem po prostu robimy:
Oczywiście w tym przypadku
Jedi
nie musi być mapowaną jednostką. Może to być zwykłe POJO.Korzystanie z mapowania XML
Należę do tych, dla których dodawanie tych wszystkich danych jest
@SqlResultSetMapping
dość inwazyjne w moich obiektach, a szczególnie nie podoba mi się definiowanie nazwanych zapytań w jednostkach, więc alternatywnie robię to wszystko wMETA-INF/orm.xml
pliku:I to są wszystkie rozwiązania, które znam. Ostatnie dwa są idealnym sposobem, jeśli możemy użyć JPA 2.1.
źródło
@SqlResultSetMapping
musi być umieszczony w encji, ponieważ właśnie z tego JPA będzie czytać metadane. Nie możesz oczekiwać, że JPA sprawdzi twoje POJO. Jednostka, w której umieszczasz mapowanie, jest nieistotna, być może ta, która jest bardziej związana z wynikami POJO. Alternatywnie odwzorowanie mogłoby być wyrażone w XML, aby uniknąć łączenia z całkowicie niepowiązaną jednostką.@SqlResultSetMapping
, warto zauważyć, żeJedi
klasa będzie wymagać konstruktora złożonego z wszystkich argumentów, a@ColumnResult
adnotacja może wymagaćtype
dodania atrybutu do konwersji, co może nie być niejawne (musiałem dodaćtype = ZonedDateTime.class
dla niektórych kolumn).Tak, z JPA 2.1 jest to łatwe. Masz bardzo przydatne adnotacje. Upraszczają Twoje życie.
Najpierw zadeklaruj swoje natywne zapytanie, a następnie mapowanie zestawu wyników (które definiuje mapowanie danych zwróconych przez bazę danych do Twoich obiektów POJO). Napisz swoją klasę POJO, do której chcesz się odwoływać (nie uwzględniono tutaj dla zwięzłości). Last but not least: utwórz metodę w DAO (na przykład), aby wywołać zapytanie. To zadziałało dla mnie w aplikacji dropwizard (1.0.0).
Najpierw zadeklaruj natywne zapytanie w klasie jednostki:
Poniżej możesz dodać deklarację mapowania zestawu wyników:
Później w DAO możesz odnieść się do zapytania jako
Otóż to.
źródło
Jeśli używasz
Spring-jpa
, jest to uzupełnienie odpowiedzi i tego pytania. Popraw to, jeśli są jakieś wady. Użyłem głównie trzech metod, aby osiągnąć „mapowanie wynikuObject[]
do pojo” w zależności od praktycznej potrzeby, jaką spełniam:sql
z jegoEntity
wystarczą.Poprzedni 2 zawiódł i muszę użyć
nativeQuery
. Oto przykłady. Oczekiwane pojo:Metoda 1 : Zmień pojo na interfejs:
I repozytorium:
Metoda 2 : Repozytorium:
Uwaga: sekwencja parametrów konstruktora POJO musi być identyczna zarówno w definicji POJO, jak i sql.
Metoda 3 : Użyj
@SqlResultSetMapping
i@NamedNativeQuery
wEntity
jako przykład w odpowiedzi na Edwina Dalorzo.Pierwsze dwie metody wywoływałyby wiele pośrednich programów obsługi, takich jak niestandardowe konwertery. Na przykład
AntiStealing
definiuje asecretKey
, zanim zostanie utrwalony, zostanie wstawiony konwerter, aby go zaszyfrować. Spowodowałoby to, że pierwsze dwie metody zwracałyby przekonwertowany powrót,secretKey
co nie jest tym, czego chcę. Chociaż metoda 3 pokonałaby konwerter, a zwróconasecretKey
byłaby taka sama, jak jest przechowywana (zaszyfrowana).źródło
Można wykonać procedurę rozpakowywania, aby przypisać wyniki do obiektu niebędącego jednostką (czyli Beans / POJO). Procedura jest następująca.
Użycie dotyczy implementacji JPA-Hibernate.
źródło
JobDTO
powinien mieć domyślny konstruktor. Lub możesz zaimplementować własny transformator w oparciu oAliasToBeanResultTransformer
implementację.Najpierw zadeklaruj następujące adnotacje:
Następnie opisz swoje POJO w następujący sposób:
Następnie napisz procesor adnotacji:
Użyj powyższej struktury w następujący sposób:
źródło
BeanUtils
w środku?Najprościej skorzystać z tak rzutów . Może mapować wyniki zapytania bezpośrednio do interfejsów i jest łatwiejszy do wdrożenia niż użycie SqlResultSetMapping.
Przykład jest pokazany poniżej:
Pola z przewidywanego interfejsu muszą być zgodne z polami w tej encji. W przeciwnym razie mapowanie pól może się zepsuć.
Również jeśli używasz
SELECT table.column
notacji, zawsze definiuj aliasy pasujące do nazw z encji, jak pokazano w przykładzie.źródło
W hibernacji możesz użyć tego kodu, aby łatwo zmapować swoje natywne zapytanie.
źródło
Korzystanie z hibernacji:
źródło
Stary styl przy użyciu zestawu wyników
źródło
Ponieważ inni już wymienili wszystkie możliwe rozwiązania, udostępniam moje rozwiązanie tymczasowe.
W mojej sytuacji z
Postgres 9.4
, pracując zJackson
,Jestem pewien, że możesz znaleźć to samo dla innych baz danych.
Również natywne wyniki zapytań FYI, JPA 2.0 jako mapa
źródło
Nie jestem pewien, czy to tutaj pasuje, ale miałem podobne pytanie i znalazłem dla mnie następujące proste rozwiązanie / przykład:
W moim przypadku musiałem użyć części SQL zdefiniowanych w Strings w innym miejscu, więc nie mogłem po prostu użyć NamedNativeQuery.
źródło
Stary styl przy użyciu zestawu wyników
źródło
Rozwiązaliśmy problem w następujący sposób:
źródło
Zobacz przykład poniżej, jak używać POJO jako pseudo encji do pobierania wyników z natywnego zapytania bez użycia złożonego SqlResultSetMapping. Potrzebujesz tylko dwóch adnotacji, gołego @Enity i fikcyjnego @Id w swoim POJO. @Id można użyć w dowolnym wybranym polu, pole @Id może mieć zduplikowane klucze, ale nie może zawierać wartości null.
Ponieważ @Enity nie mapuje na żadną fizyczną tabelę, więc ten POJO nazywany jest pseudoobiektem.
Środowisko: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Możesz pobrać cały projekt maven tutaj
Natywne zapytanie jest oparte na przykładowych pracownikach mysql db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
źródło
list
jest rzekomo listąEmployee
, dlaczego twoja pętla for-each iteruje po typieObject
? Jeśli napiszesz pętlę for-each, ponieważfor(Employee emp : list)
wtedy odkryjesz, że twoja odpowiedź jest błędna, a zawartość listy nie dotyczy pracowników, a to ostrzeżenie, które ukryłeś, miało na celu ostrzeżenie cię o tym potencjalnym błędzie.List<Employee> list = (List<Employee>) query.getResultList();
Zmieńfor (Object emp : list)
nafor (Employee emp : list)
jest lepsza, ale nie ma błędów, jeśli jest przechowywana,Object emp
ponieważ lista jest wystąpieniemList<Employee>
. Zmieniłem kod w projekcie git, ale nie tutaj, aby Twój komentarz odnosił się do oryginalnego postuQuery query = em.createNativeQuery("select * ...", Employee.class);
i persistence.xml, natywne zapytanie zwraca listę Pracownik. Właśnie sprawdziłem i uruchomiłem projekt bez problemu. Jeśli ustawisz lokalnie bazę danych pracowników przykładowych mysql, powinieneś być w stanie uruchomić projektEmployee
jak przypuszczam, bytu. Prawda?jeśli używasz Spring, możesz użyć
org.springframework.jdbc.core.RowMapper
Oto przykład:
źródło
Korzystanie z hibernacji:
źródło
Prosty sposób na konwersję zapytania SQL do kolekcji klas POJO,
źródło
Wszystko czego potrzebujesz to DTO z konstruktorem:
i nazwij to:
źródło
Użyj
DTO Design Pattern
. Został użyty wEJB 2.0
. Jednostka była zarządzana przez kontener.DTO Design Pattern
służy do rozwiązania tego problemu. Ale może być używany teraz, gdy aplikacja jest rozwijanaServer Side
iClient Side
oddzielnie.DTO
jest używany, gdyServer side
nie chce przekazać / powrócićEntity
z adnotacją doClient Side
.Przykład DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- to mide be need
źródło