3.1 Bevezetés

Egy másik hasznos dolog, amiről szeretnék beszélni, a NativeQuery . Mint már tudja, a NativeQuery használatával natív SQL-ben írhat lekérdezéseket. Azonban ami még érdekesebb, hogy nem kell osztályleképezést használnia a lekérdezés eredményének lekérésekor.

Inkább mutatok egy példát:

List<Object[]> persons = session.createNativeQuery("SELECT * FROM Person").list();

Ebben a példában nem adunk át olyan osztályt, amely megfelel a lekérdezés eredménysorainak, ehelyett csak egy Object objektumok tömbjét használjuk.

Ez akkor lehet hasznos, ha csak néhány oszlopot szeretne kijelölni egy táblázatban. Példa:


List<Object[]> persons = session.createNativeQuery("SELECT id, name FROM Person").list();
 
for(Object[] person : persons) {
    Number id = (Number) person[0];
    String name = (String) person[1];
}

Ez némileg hasonlít a JDBC megközelítéshez, amikor egy ResultSet objektumot kap, és adatokat olvas ki a soraiból.

A Hibernate azonban különféle módokat kínál ennek megbízhatóbbá tételére. Például megadhatja a kivonni kívánt oszlopok típusát. Példa:


Query<Object[]> query = session.createNativeQuery("SELECT id, name FROM Person");
query.addScalar("id", StandardBasicTypes.LONG);
query.addScalar("name", StandardBasicTypes.STRING);
List<Object[]> persons = query.list();
 
for(Object[] person : persons) {
    Long id = (Long) person[0];
    String name = (String) person[1];
}

3.2 Entitásleképezés

Explicit módon megadhatja azt az osztályt is, amelyet a Hibernate használjon a NativeQuery eredményének elemzésekor . Ezt különböző módon lehet megtenni.


Query<Person> query = session.createNativeQuery("SELECT * FROM Person")
    .addEntity(Person.class);
    .list();

És persze a régi jó formátum, amit ismersz:


Query<Person> query = session.createNativeQuery("SELECT * FROM Person", Person.class).list();

Az első megközelítés a natív hibernált megközelítés, a második pedig a JPA megközelítés. A JPA megközelítés kényelmesebb és tömörebb, mivel ezt a szabványt azután találták fel, hogy a Hibernate sok éven át létezett. A Hibernate pedig fejlődött, és kénytelen volt támogatni a régi megközelítéseket, hogy fenntartsa a kompatibilitást a régi verzióival.

A Hibernate egyébként megközelítésének köszönhetően nem egy osztályt, hanem több osztályt is lehetővé tesz a lekérdezési eredményleképezéshez. Példa:


List<Phone> results = session.createNativeQuery(
    "SELECT {ph.*}, {pr.*}" +
    "FROM Phone ph" +
    "JOIN Person pr ON ph.person_id = pr.id")
.addEntity("ph", Phone.class)
.addJoin("pr", "ph.person")
.list();
 
for (Phone. phone : results) {
           	assertNotNull( phone.getPerson().getName() );
}

Ez a NativeQuery-t használó megközelítés felgyorsíthatja az adatok kiválasztását az adatbázisból. Ha tudja, hogy nincs szüksége néhány oszlopra, elhagyhatja őket a kérésben.

Az összes gyermek entitást egyszerre is betöltheti, még akkor is, ha a Hibernate a gyorsítótárat vagy a LazyLoading mechanizmust szeretné használni . Ezenkívül az alárendelt entitások sok oszlopot tartalmazhatnak az adatbázisban, és ezek közül csak néhányat választhat ki.

3.3 DTO leképezés

A hibernálás lehetővé teszi nem Entity osztályok használatát is az eredmény leképezéséhez. Osztályok, amelyek nem rendelkeznek megjegyzésekkel, és nincsenek hozzárendelve egyetlen táblázathoz sem.

Példa:

public class PersonSummaryDTO {
    private Number id;
    private String name;

    public Number getId() {
    	return id;
    }

    public void setId(Number id) {
    	this.id = id;
    }

    public String getName() {
    	return name;
    }

    public void setName(String name) {
    	this.name = name;
	}
}

List<PersonSummaryDTO> dtos = session.createNativeQuery(
    "SELECT p.id as \"id\", p.name as \"name\" FROM Person p")
.setResultTransformer(Transformers.aliasToBean(PersonSummaryDTO.class) )
.list();

Mivel a PersonSummaryDTO osztályban nincsenek megjegyzések, az SQL lekérdezés oszlopainak nevének pontosan meg kell egyeznie a PersonSummaryDTO osztály mezőinek nevével.

Ez nagyon hasznos lehet, ha olyan külső adatbázisból olvas adatokat, amelyhez az alkalmazás csak olvasható módban csatlakozik. Vagyis olyan táblákhoz kaptál hozzáférést, amelyek 50+ oszlopot tartalmaznak, denormalizált formában tárolják az adatokat, hogy felgyorsítsák a kijelölést.

Vagy tegyük fel, hogy valaki úgy döntött, hogy egy táblázatban tárolja az osztályhierarchiát, és öt év alatt ez a táblázat annyira megnőtt, hogy az ördög eltöri a lábát. Ebből a táblázatból ki kell választani néhány oszlopot (Id és username), és át kell adni az ügyfélnek.

Szerintem érted, de ha szeretnél mélyebbre merülni ebben a témában, akkor a linken olvashatsz bővebben:

Natív SQL-lekérdezések