3.1 Introducere

Un alt lucru util despre care aș dori să vorbesc este NativeQuery . După cum știți deja, folosind NativeQuery, puteți scrie interogări în SQL nativ. Cu toate acestea, ceea ce este și mai interesant este că nu trebuie să utilizați maparea claselor când obțineți rezultatul interogării.

Aș prefera să vă arăt un exemplu:

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

În acest exemplu, nu trecem o clasă care se potrivește cu rândurile de rezultat al interogării, ci doar folosim o matrice de obiecte Object.

Acest lucru poate fi util dacă doriți să selectați doar câteva coloane într-un tabel. Exemplu:


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];
}

Acest lucru este oarecum similar cu abordarea JDBC atunci când obțineți un obiect ResultSet și citiți datele din rândurile sale.

Cu toate acestea, Hibernate oferă diferite moduri de a face acest lucru mai fiabil. De exemplu, puteți specifica tipul de coloane pe care doriți să le scădeți. Exemplu:


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 Maparea entităților

De asemenea, puteți specifica în mod explicit clasa pe care Hibernate ar trebui să o utilizeze atunci când parsează rezultatul NativeQuery . Acest lucru se poate face în moduri diferite.


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

Și, desigur, vechiul format bun pe care îl cunoașteți:


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

Prima abordare este abordarea nativă Hibernate, iar a doua este abordarea JPA. Abordarea JPA este mai convenabilă și mai concisă, deoarece acest standard a fost inventat după ce Hibernate a existat de mulți ani. Și Hibernate a evoluat și a fost forțat să accepte abordări vechi pentru a menține compatibilitatea cu versiunile sale vechi.

Apropo, datorită abordării sale, Hibernate vă permite să conectați nu o singură clasă la maparea rezultatelor interogării, ci mai multe clase. Exemplu:


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() );
}

Această abordare folosind NativeQuery poate fi folosită pentru a accelera selecția datelor din baza de date. Dacă știți că nu aveți nevoie de niște coloane, le puteți lăsa afară în cerere.

De asemenea, puteți încărca toate entitățile copil simultan, chiar dacă Hibernate dorește să folosească Cache sau mecanismul LazyLoading . În plus, entitățile dumneavoastră copil pot avea multe coloane în baza de date și puteți selecta doar câteva dintre ele.

3.3 Maparea DTO

Hibernate vă permite, de asemenea, să utilizați clase non-Entity pentru maparea rezultatului. Clase care nu au adnotări și nu sunt mapate la niciun tabel.

Exemplu:

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();

Deoarece nu există adnotări în clasa PersonSummaryDTO, numele coloanelor din interogarea SQL trebuie să se potrivească exact cu numele câmpurilor din clasa PersonSummaryDTO.

Acest lucru poate fi foarte util dacă citiți date dintr-o bază de date externă la care aplicația dvs. este conectată numai în modul doar citire. Adică, vi s-a dat acces la tabele care au peste 50 de coloane, acestea stochează date într-o formă denormalizată pentru a accelera selecția.

Sau să zicem că cineva a decis să stocheze ierarhia clasei într-un singur tabel, iar în cinci ani acest tabel a crescut atât de mult încât diavolul își va rupe piciorul. Trebuie să selectați câteva coloane din acest tabel (Id și nume de utilizator) și să le oferiți clientului.

Cred că înțelegi, dar dacă vrei să aprofundezi acest subiect, poți citi mai multe la link:

Interogări SQL native