JOIN in CriteriaQuery

JEEntleman

Mitglied
Hallo alle,
Ich benutze JPA 2.0 mit der statndard implementierung dafür. Ich habe in UI eine Tabelle mit Paginierung, die sortiert werden kann. Nun wollte ich mit NamedQueries die" ORDER BY :fieldname :sortorder" probieren, habe aber erfahren dass es nicht geht.

dh. ich übergebe der DAO Methode (int first, int maxRes, String sortColName, ASC / DESC) und will die PERSONEN haben.
Das Problem ist dass es eine Spalte ROLLE gibt eine Person kann WORKER id 1, MANAGER id 2 usw haben (Tabelle Role (id,rolename ) ) - wenn ich nach role sortieren will kracht es. DA brauche ich ein Join. Ich will es aber Typischer und als Letztes will ich ne Query konkatenieren. Ich habe mit CriteriaQueries probiert aber komme mit den Joins nicht klar.
Ich bräuchte also solche Query:
SELECT p FROM Person p LEFT JOIN Role r WHERE 1
ORDER BY r.name LIMIT firts, maxRes

r.name gibt es nur in role, person hat solhces feld nicht aber es kann auch nach p.lastname oder p. firstname sortiert werden.

Als nächstes kommt noch weitere Einschränkung und zwar ein Where welches sich nur auf die Person bezieht, sich Where p.firstname Like %suchwort%

Konnte mir jemand sagen wie man dafür eine CriteriaQuery baut bzw etwas was auch typsicher ist und performancetechnisch ok ist.

Danke im Voraus
 

KSG9|sebastian

Top Contributor
Hi,

zum einen hättest du mit Google innerhalb von ein paar Sekunden gefunden. Zum anderen wäre es einfacher zu verstehen wenn du ein wenig auf deine Schreibweise achten würdest.

Hier mal ein Codebeispiel mit Joins:

Code:
CriteriaBuilder criteriaBuilder =  entityManagerFactory.getCriteriaBuilder();
CriteriaQuery<Department> query2 = criteriaBuilder.createQuery(Department.class) ;
Root<Department> departmen1R = query2.from(Department.class) ;
Join<Object, Object> employee1J = departmen1R.join("employees") ;
Join<Object, Object> project1J = employee1J.join("projects") ;
Predicate name1P =  criteriaBuilder.equal(project1J.get("name") ,  "Design Release2") ;
query2.select(departmen1R).where(name1P).distinct(true) ;
List<Department> resultList2 =  entityManager.createQuery(query2).getResultList( ) ;
for (Department department : resultList2) {
   System.err.println(department) ;
}

Quelle: http://www.buschmais.de/media/2010/07/jugsaxony_jpa2-criteria.pdf
 

JEEntleman

Mitglied
Hi, sorry für die ganzen Fehler, aber ich habe es quasi mit ausgeschaltetem Brain geschrieben.
Ich muss sogar zugeben dass ich die PDF Datei auch mal angeguckt habe und das konnte mir daraus ich nichts sinnvolles herausziehen.
Ausserdem habe ich erst nach ausgebiegen suchen den Post geschrieben. Ich habe halt nichts, für meinen Fall, passendes gefunden.
Ich Danke dennoch sehr, das sich jemand gefunden hat und mir mit dem Tipp geholfen hat. Manchmal sieht man den Wald vor lauter Bäume nicht mehr. Vielen dank !

Ich habe nun das Beispiel umgebaut so dass es funktioniert, aber leider mit einem if.
Wenn ich mich auf das obere Beispiel beziehe und nur ein Join verwende sieht das abschließende SELECT so aus:
Ich habe meine Entitäten eingesetzt - und es ist in meine Fall umgekehrt:
im Bsp:
Dep - Employees 1:n
Dep - projects 1:n
bei mir
Person - Role n:1 (bei mir kann die Person nur eine Rolle haben)

Code:
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Person> query2 = criteriaBuilder.createQuery(Person.class) ;
		Root<Person> departmen1R = query2.from(Person.class) ;
		Join<Object, Object> employee1J = departmen1R.join("role") ;

if(sortCol.equals("role")){			
			query2.select(departmen1R).distinct(true).orderBy( isAscending ? criteriaBuilder.asc(employee1J.get("title")) : criteriaBuilder.desc(employee1J.get("title"))) ;
		}else{
			query2.select(departmen1R).distinct(true).orderBy( isAscending ? criteriaBuilder.asc(departmen1R.get(sortCol)) : criteriaBuilder.desc(departmen1R.get(sortCol))) ;
		}

In der UI Tabelle kann man wie gesagt nach firstname, lastname und role sortieren
diese schickt dann Requests mit dem PropertyName welches in die DAO funktion deren Parameter ich im ersten Post geschrieben habe.
Sortiere ich nach firstname so kommt nach jedem Klick firstname und abwechselnd true/false in die Funktion übergeben.

So wie ich es momentan sehe muss ich jedes mal unterscheiden welchem Entity das zu sortierende Column gehört und dann entweder Root oder Join für orderBy benutzen. Dabei muss ich bei den Joins noch den entsprechenden Columnname angeben - so musste ich in dem if(sortCol.equals("role")) prüfen ob es sich um das Entity role handelt wenn ja, dann soll es nach role.title sortiert werden.

Kann man das vereinfachen (Zumindest für den einfachen fall)?
Momentan muss ich nur zwischen 2 Entitäten unterscheiden (Person und Role), aber wenn ich mehr haben werden, dann kommen weitere if's
Da dies die Personen Tabelle ist, weiss ich zumindest, dass mit role, die Role Entity gemeint ist, wenn da jetzt Adresse dazu kommt, dann könnte es schwieriger werden, wenn ich auf einmal separat strasse und PLZ in der Tabelle anzeige und danach sortieren will.
 
N

nillehammer

Gast
Hallo JEEntleman,
Dein UseCase sieht mir danach aus, als solltest Du statt mit ORDER BY auf DB-Ebene lieber mit Comparatoren auf Java-Ebene arbeiten. Also, bei Selektieren der Sortierkriterien einen entsprechenden Comparator erzeugen und den dann auf die Ergebnisliste Deiner Query anwenden, z.B mit der Methode sort aus der Klasse Collections: Collections#sort(..) (Java 2 Platform SE 5.0)

Eine andere Möglichkeit wäre, den HQL/SQL-String mit dem ORDER BY-Teil dynamisch zusammenzubauen und dann erst die Query daraus zu bauen. NamedQuery geht dann natürlich nicht, ist in meinen Augen aber eh ein sinnloses Feature.
 
Zuletzt bearbeitet von einem Moderator:

JEEntleman

Mitglied
Das habe ich überlegt,
wenn ich 10K Datensätze kurz mal sortieren muss, ist das suboptimal. Mit meiner Query bekomme ich 10/25/50 Results, die dann auch sortiert sind. Ich habe es nicht getestet aber ich denke dass es nicht so kostbar ist die Query zu Bauen + max 50 Objekte zu instantiieren als 10K zu sortieren. Die Table lädt nämlich die Sachen Häppchenweise per AJAX nach sobald man auf weiter oder entsprechende Page im Paginator klickt. Mit NamedQueries hat man den Vorteil gehabt dass man den QueryString nicht jedes mal Bauen muss. Hmmm ich habe jetzt jOOQ gefunden, damit würde ich zumindest die Typsicherheit hinbekommen, aber müsste wahrscheinlich auch viel zu viel umbauen müssen. Ich bleibe wohl erstmal bei der unschönen Variante die funzt bis mir was besseres einfällt, oder jemand noch einen anderen Ausweg vorschlägt.

Danke
 

Ähnliche Java Themen


Oben