Bevezetés a Querydsl-be

1. Bemutatkozás

Ez egy bevezető cikk, amely használatba veszi az erőteljes Querydsl API-t az adatok tartóssága érdekében.

A cél itt az, hogy gyakorlati eszközöket adjon a Querydsl hozzáadásához a projektbe, megértse a generált osztályok felépítését és célját, valamint alapvető ismereteket szerezzen a tipikusan biztonságos adatbázis-lekérdezések írásáról a leggyakoribb esetekhez.

2. A Querydsl célja

Az objektum-relációs leképezési keretrendszerek az Enterprise Java alapját képezik. Ezek kompenzálják az objektum-orientált megközelítés és a relációs adatbázis-modell közötti eltéréseket. Ezenkívül lehetővé teszik a fejlesztők számára, hogy tisztább és tömörebb perzisztencia kódot és tartományi logikát írjanak.

Az ORM-keretrendszer egyik legnehezebb tervezési döntése a helyes és típusbiztonságos lekérdezések létrehozásának API-ja.

Az egyik legszélesebb körben használt Java ORM keretrendszer, a Hibernate (és a szorosan kapcsolódó JPA szabvány) az SQL-hez nagyon hasonló, string alapú lekérdező nyelvet, HQL (JPQL) javasol. Ennek a megközelítésnek nyilvánvaló hátránya a típusbiztonság hiánya és a statikus lekérdezés-ellenőrzés hiánya. Ezenkívül bonyolultabb esetekben (például amikor a lekérdezést futási időben kell összeállítani, bizonyos feltételektől függően), a HQL lekérdezés felépítése általában a karakterláncok összefűzésével jár, ami általában nagyon nem biztonságos és hibára hajlamos.

A JPA 2.0 szabvány javulást hozott a Criteria Query API formájában - egy új és típusbiztos módszer a lekérdezések elkészítéséhez, amely kihasználta az annotáció előtti feldolgozás során létrehozott metamodell osztályokat. Sajnos, mivel lényegében úttörő volt, a Criteria Query API nagyon bőbeszédű és gyakorlatilag olvashatatlan. Itt van egy példa a Jakarta EE oktatóanyagból, amellyel olyan egyszerű lekérdezést állíthat elő, mint KIVÁLASZTÁS P A KISállatból:

EntityManager em = ...; CriteriaBuilder cb = em.getCriteriaBuilder (); CriteriaQuery cq = cb.createQuery (Pet.class); Gyökérállat = kb. (Pet.osztály); cq.select (kisállat); TypedQuery q = em.createQuery (cq); List allPets = q.getResultList ();

Nem csoda, hogy hamarosan létrejött egy megfelelőbb Querydsl-könyvtár, amely a létrehozott metaadat-osztályok ugyanazon elképzelésén alapult, mégis folyékony és olvasható API-val valósult meg.

3. Querydsl osztály generálása

Kezdjük a Querydsl folyékony API-ját kitevő mágikus metaclasserek előállításával és feltárásával.

3.1. Querydsl hozzáadása a Maven Buildhez

A Querydsl felvétele a projektbe olyan egyszerű, mint több függőség hozzáadása a build fájlhoz, és egy plugin konfigurálása a JPA kommentárok feldolgozásához. Kezdjük a függőségekkel. A Querydsl könyvtárak verzióját külön tulajdonságba kell kicsomagolni a szakasz az alábbiak szerint (a Querydsl könyvtárak legújabb verziójához nézze meg a Maven Central adattárat):

 4.1.3 

Ezután adja hozzá a következő függőségeket a szakasza pom.xml fájl:

  com.querydsl querydsl-apt $ {querydsl.version} megadott com.querydsl querydsl-jpa $ {querydsl.version} 

A querydsl-apt A dependence egy annotáció-feldolgozó eszköz (APT) - a megfelelő Java API megvalósítása, amely lehetővé teszi a forrásfájlokban lévő annotációk feldolgozását, mielőtt azok a fordítási szakaszba lépnének. Ez az eszköz úgynevezett Q-típusokat generál, amelyek közvetlenül kapcsolódnak az alkalmazás entitásosztályaihoz, de előtagjuk Q betű. Például, ha van egy Felhasználó osztály, amelyet a @Entity jelölés az alkalmazásban, akkor a létrehozott Q-típus a-ban fog tartózkodni QUser.java forrás fájl.

A biztosítani a querydsl-apt A függőség azt jelenti, hogy ezt az edényt csak a készítés idején szabad elérhetővé tenni, de nem kell feltüntetni az alkalmazás műtermékében.

A querydsl-jpa könyvtár maga a Querydsl, amelyet JPA alkalmazással együtt terveztek használni.

Annotation processing plugin konfigurálásához, amely kihasználja querydsl-apt, adja hozzá a következő plugin konfigurációt a csomagjához - a elem:

 com.mysema.maven apt-maven-plugin 1.1.3 folyamat cél / generált források / java com.querydsl.apt.jpa.JPAAnnotationProcessor 

Ez a beépülő modul biztosítja, hogy a Q-típusok a Maven build folyamatcélja során keletkezzenek. A kimeneti könyvtár A konfigurációs tulajdonság arra a könyvtárra mutat, ahol a Q típusú forrásfájlok generálódnak. A tulajdonság értéke később hasznos lesz, amikor felfedezi a Q-fájlokat.

Ezt a könyvtárat hozzá kell adnia a projekt forrásmappáihoz is, ha az IDE nem teszi ezt automatikusan - ennek módjáról olvassa el a kedvenc IDE dokumentációját.

Ebben a cikkben egy blogszolgáltatás egyszerű JPA modelljét fogjuk használni, amely a következőkből áll: Felhasználók és övék BlogPosts a többiekkel való kapcsolat között:

@Entity public class User {@Id @GeneratedValue private Long id; privát karakterlánc bejelentkezés; privát logikai letiltva; @OneToMany (cascade = CascadeType.PERSIST, mappedBy = "user") private Set blogPosts = new HashSet (0); // getters and setters} @Entity public class BlogPost {@Id @GeneratedValue private Long id; privát húr cím; privát húr test; @ManyToOne magánfelhasználó felhasználó; // szerelők és beállítók}

Q-típusok létrehozásához a modelljéhez egyszerűen futtassa:

mvn össze

3.2. Generált osztályok felfedezése

Most lépjen a. Könyvtárban megadott könyvtárba kimeneti könyvtár tulajdonság az apt-maven-plugin (target / generated-sources / java példánkban). Megjelenik egy csomag- és osztálystruktúra, amely közvetlenül tükrözi a tartománymodelljét, kivéve, hogy az összes osztály Q betűvel kezdődik (QUser és QBlogPost a mi esetünkben).

Nyissa meg a fájlt QUser.java. Ez a belépési pont az összes lekérdezés elkészítéséhez Felhasználó mint gyökér entitás. Első dolog, amit észrevesz, az a @ Generált megjegyzés, ami azt jelenti, hogy ez a fájl automatikusan jött létre, és nem szabad manuálisan szerkeszteni. Ha valamelyik tartománymodell osztályát megváltoztatja, futtatnia kell mvn össze ismét a megfelelő Q-típusok regenerálásához.

Többet leszámítva QUser konstruktorok jelen vannak ebben a fájlban, akkor vegye figyelembe a nyilvános statikus végső példányát is QUser osztály:

public static final QUser felhasználó = új QUser ("felhasználó");

Ez az a példa, amelyet a legtöbb Querydsl lekérdezéskor használhat ennél az entitásnál, kivéve, ha összetettebb lekérdezéseket kell írnia, például egy tábla több különböző példányát kell összekapcsolnia egyetlen lekérdezésben.

Utoljára meg kell jegyezni, hogy az entitásosztály minden mezőjéhez tartozik egy megfelelő *Pálya mező a Q-típusú, tetszik NumberPath id, StringPath bejelentkezés és SetPath blogPosts ban,-ben QUser osztály (vegye figyelembe, hogy a mezőnek a Készlet pluralizált). Ezeket a mezőket a folyékony lekérdezés API részeként használják, amelyekkel később találkozunk.

4. Lekérdezés a Querydsl segítségével

4.1. Egyszerű lekérdezés és szűrés

Lekérdezés összeállításához először egy a példányra lesz szükségünk JPAQueryFactory, amely az építési folyamat megkezdésének előnyös módja. Az egyetlen dolog JPAQueryFactory igények egy EntityManager, amelynek már elérhetőnek kell lennie a JPA alkalmazásában a következő címen: EntityManagerFactory.createEntityManager () hívás vagy @PersistenceContext injekció.

EntityManagerFactory emf = Persistence.createEntityManagerFactory ("com.baeldung.querydsl.intro"); EntityManager em = entitásManagerFactory.createEntityManager (); JPAQueryFactory queryFactory = új JPAQueryFactory (em);

Most hozzuk létre az első lekérdezést:

QUser felhasználó = QUser.user; C felhasználó = queryFactory.selectFrom (user) .where (user.login.eq ("David")) .fetchOne ();

Vegye figyelembe, hogy definiáltunk egy helyi változót QUser felhasználóval inicializálta QUser.user statikus példány. Ez pusztán a rövidség érdekében történik, vagy importálhatja a statikát QUser.user terület.

A válasszon módszere JPAQueryFactory elkezdi létrehozni a lekérdezést. Átadjuk a QUser példány, és folytassa a lekérdezés feltételes záradékának felépítését a .hol() módszer. A bejelentkezés hivatkozás a StringPath mező QUser osztály, amelyet már láttunk. A StringPath objektumnak is van .eq () módszer, amely lehetővé teszi a lekérdezés gördülékeny folytatását a mezőegyenlőség feltételének megadásával.

Végül, hogy az értéket lekérjük az adatbázisból a perzisztencia kontextusába, befejezzük az építési láncot a fetchOne () módszer. Ez a módszer visszatér nulla ha az objektum nem található, de dob egy NonUniqueResultException ha több entitás elégíti ki a .hol() feltétel.

4.2. Rendelés és csoportosítás

Most keressük meg az összes felhasználót egy listában, belépésük szerint rendezve, felemelkedési sorrendben.

Sorolja fel a c = queryFactory.selectFrom (user) .orderBy (user.login.asc ()) .fetch () listát;

Ez a szintaxis azért lehetséges, mert a *Pálya osztályok a .asc () és .desc () mód. Több argumentumot is megadhat a .Rendezés() módszer több mező szerinti rendezéshez.

Most próbálkozzunk valami nehezebbel. Tegyük fel, hogy az összes bejegyzést cím szerint kell csoportosítanunk, és meg kell számolnunk az ismétlődő címeket. Ez a .csoportosít() kikötés. Azt is meg akarjuk rendezni a címek alapján, hogy az előfordulások száma mennyi.

NumberPath count = Expressions.numberPath (hosszú.osztály, "c"); List userTitleCounts = queryFactory.select (blogPost.title, blogPost.id.count (). As (count)) .from (blogPost) .groupBy (blogPost.title) .orderBy (count.desc ()) .fetch ();

Kiválasztottuk a blogbejegyzés címét és az ismétlések számát, cím szerint csoportosítva, majd összesített szám szerint rendezve. Figyelem: először létrehoztunk egy álnevet a számol() mező a.válassza () záradékot, mert hivatkoznunk kellett rá a .Rendezés() kikötés.

4.3. Összetett lekérdezések összekapcsolásokkal és részlekérdezésekkel

Találjuk meg az összes felhasználót, aki írt egy bejegyzést „Hello World!” Címmel. Ilyen lekérdezéshez használhatunk belső csatlakozást. Vegyük észre, hogy létrehoztunk egy álnevet blog bejegyzés hogy az összekapcsolt táblázat hivatkozhasson rá a .tovább() kikötés:

QBlogPost blogPost = QBlogPost.blogPost; Sorolja fel a felhasználókat = queryFactory.selectFrom (user) .innerJoin (user.blogPosts, blogPost) .on (blogPost.title.eq ("Hello World!")) .Fetch ();

Most próbáljuk meg ugyanezt elérni az allekérdezéssel is:

Felsorolja a felhasználókat = queryFactory.selectFrom (user) .where (user.id.in (JPAExpressions.select (blogPost.user.id) .from (blogPost) .where (blogPost.title.eq ("Hello World!"))) ) .hívás ();

Mint láthatjuk, az al lekérdezések nagyon hasonlítanak a lekérdezésekre, és eléggé olvashatóak is, de azzal kezdődnek JPAExpressions gyári módszerek. Ahhoz, hogy az alkérdezéseket a fő lekérdezéssel összekapcsoljuk, mint mindig, a korábban definiált és használt álnevekre hivatkozunk.

4.4. Adatok módosítása

JPAQueryFactory lehetővé teszi nemcsak a lekérdezések összeállítását, hanem a rekordok módosítását és törlését is. Változtassuk meg a felhasználó bejelentkezését és tiltsuk le a fiókot:

queryFactory.update (user) .where (user.login.eq ("Ash")) .set (user.login, "Ash2") .set (user.disabled, true) .execute ();

Bármennyi lehet .készlet() különböző területekre vonatkozó záradékokat. A .hol() záradék nem szükséges, ezért az összes rekordot egyszerre frissíthetjük.

Egy bizonyos feltételnek megfelelő rekordok törléséhez hasonló szintaxist használhatunk:

queryFactory.delete (user) .where (user.login.eq ("David")) .execute ();

A .hol() záradék szintén nem szükséges, de légy óvatos, mert a .hol() záradék egy bizonyos típusú entitás törlését eredményezi.

Kíváncsi lehet, miért JPAQueryFactory nem rendelkezik a . beszúrás () módszer. Ez a JPA Query felület korlátozása. A mögöttes javax.persistence.Query.executeUpdate () metódus képes végrehajtani a frissítést és a törlést, de nem lehet utasításokat beszúrni. Adatok beszúrásához egyszerűen meg kell őriznie az entitásokat az EntityManager alkalmazással.

Ha továbbra is ki akarja használni egy hasonló Querydsl szintaxis előnyeit az adatok beszúrásához, akkor használja SQLQueryFactory osztály, amely a querydsl-sql könyvtárban található.

5. Következtetés

Ebben a cikkben egy erőteljes és típusbiztos API-t fedeztünk fel a perzisztens objektumkezeléshez, amelyet a Querydsl biztosít.

Megtanultuk hozzáadni a Querydsl-t a projekthez, és feltártuk a generált Q-típusokat. Kitértünk néhány tipikus használati esetre, és élveztük tömörségüket és olvashatóságukat.

A példákhoz tartozó összes forráskód megtalálható a github adattárban.

Végül természetesen a Querydsl számos további funkcióval rendelkezik, beleértve a nyers SQL-sel való munkát, a nem állandó gyűjteményeket, a NoSQL adatbázisokat és a teljes szöveges keresést - ezek egy részét a jövőbeni cikkekben fogjuk megvizsgálni.


$config[zx-auto] not found$config[zx-overlay] not found