Strona główna > Java > Opakowanie wynik zapytani JPA do DTO

Opakowanie wynik zapytani JPA do DTO

Ten wpis jest rodzajem koncepcji (życzenia) pewnego usprawnienia jakie by mi się przydało przy pracy z JPA. Może to być także usystematyzowaniem tego co chcę i odkryciem, że problem i ewentualne rozwiązanie leży gdzie indziej.

Pisząc ostatnio zapytania w JPA (stary sposób) typu:

List persons = entityManager.createQuery("SELECT p FROM Person p").getResultList();

Miałem potrzebę, głównie ze względów wydajnościowych, ograniczenia zwracanych szczegółów w obiektach. Można to zrobić poprzez użycie DTO i wydania odpowiedniego zapytania do napełnienia pożądanych wartości w nim. Ja ze względu na zastany kod (wprowadzenie nowej klasy propagowałoby zmian wyżej) i wygody chciałem użyć wcześniejszą klas encji w tej roli. Co wygląda jak poniżej:

List persons = entityManager.createQuery("SELECT new Person(p.id, p.name) FROM Person p").getResultList();

No i jest, i dział, ale w moim (rzeczywistym) przypadku wiązało się to z przekazaniem większej liczby wartości i także stworzeniem odpowiedniego konstruktora. Czyli dużo klepania kodu w zapytaniu oraz w kodzie konstruktora. Są dwa odległe miejsca zależne od siebie, przez to można łatwo wprowadzić błąd. W przypadku gdy konstruktor przyjmuje 10 stringów, pomyłka w przypisaniu tych wartości może być łatwa do wprowadzona (choćby przestawienie dwóch wartość o tym samym typie).

Problem
Tak więc cała koncepcja ulepszenia tego sprowadza się do odpowiedzenia na pytanie: Czy nie można tego jakoś wyrazić w jednolity sposób? Tak aby mieć pewność, że konstruktor dobrze przypisuję wartości, i zapytanie jest dobrze złożone.
Dotychczas trzymałem oba kawałki kodu obok siebie, tak aby łatwiej widzieć ewentualne błędy. Później wprowadziłem automat do budowania stringa konstruktora, który eliminował pewne pomyłki (można było na przykład wprowadzić sprawdzenie czy konstruktor wyrażony w stringu da się odnaleźć). Rozwiązania te nie są idealne i są kłopotliwe w implementacji.

Uaktualnienie: poniżej są dywagacje jak to chciałbym zrobić – znalazłem rozwiązanie tego problemu w trochę inny sposób. Materiały mówiące o tym tu lub tu. A to jak później zrobiłem na podstawie tego tutaj.

Potencjalne rozwiązanie
Ostatnio zapoznałem się z nowymi sposobami wyrażania się w kodzie, skłoniło mnie to do stworzenia koncepcji jak poniżej.

Załóżmy, że pożądany konstruktor nie istniej, i nie jest nam on do niczego potrzebny oprócz użycia w zapytaniu. I chcemy żeby w tym zapytaniu był on użyty poprawnie. To nam zapewnia dwa miejsca, które są naprawdę ważne. Liczy się tylko to co się dzieje w konstruktorze i poprawne przypisanie wartości. Wyrazić można to w taki sposób:

		ConstructorCreator<Person> creator = new ConstructorCreator<Person>(){
			Person baseObject;
			public void inConstructor(Person returnObject) {
				returnObject.id = baseObject.id;
				returnObject.name = baseObject.name;
			}
		};
		creator.makeItHappens();

Przyjmijmy że makeItHappens zapewni stworzenie odpowiedniego konstruktora.
Poniższa linijka zapewni zwrócenie odpowiedniego stringa reprezentującego ten konstruktor, gotowego do użycia w zapytaniu:

String stringConstructor = creator.getStringConstructor("p");

A całość magicznego kodu byłaby zamknięta w tym:

	public class ConstructorCreator<T> {
		public abstract void inConstructor(T returnObject);
		public void makeItHappens(){
			// coć co sprawi że odpowiedni konstrukot się pojawi
		}
		public String getStringConstructor(String prefix){
			// coś co da prawidłowego stringa do zapytania, 
			// na podstawie stworzonego konstruktora
			return null;
		}
	}

Wszystko to sprawiałoby że pojawiłby się odpowiedni konstruktor:

		public Person(String id, String name) {
			this.id = id;
			this.name = name;
		}

A zwracany string miałby postać:

String stringConstructor = " new Person(p.id, p.name) ";

Jak to zrobić?
Ostatnie poszukiwania sprawiły że wydaje mi się to osiągalne. Dzięki temu co opisałem tu, a to jak generować konstruktor sądze że znalazłbym gdzieś w kodzie Hibernate. Choć to koncepcja, ale zobaczę czy da się to zrobić i z jakim skutkiem🙂.

Kategorie:Java Tags: ,
  1. Brak komentarzy.
  1. No trackbacks yet.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

%d bloggers like this: