Entity Manager

A Wikipédiából, a szabad enciklopédiából

Az Entity Manager (továbbiakban EM) a Java Persistence API része, amely segítségével objektumok (entitások) perzisztálását lehet elvégezni. A JPA specifikáció azt a problémát próbálja megoldani, hogy hogyan tudunk leképezni objektum orientált környezetből származó osztályokat relációs adatbázis táblákra és objektumokat tábla rekordokra. A Hibernate EntityManager implementálja azokat a programozási interfészeket, amelyeket a JPA 2.0-s szabvány definiál. A JPA az üzleti alkalmazások fejlesztésére szánt Java EE platform része, és az EJB 3.x típusú konténekerekben használható.

Az EntityManager interfész[szerkesztés]

Az EntityManager interfész a javax.persistence csomagban található és egy perzisztencia kontextussal való interakcióra szolgál. Egy EntityManager példány össze van kapcsolva egy ilyen kontextussal. Egy perzisztencia kontextus egyedek egy halmaza, amelyben minden egyednek van egy egyedi azonosítója. A perzisztencia kontextuson belül az egyedek és az ő életciklusok menedzselve van. Ez az interfész definiálja azokat a metódusokat, amelyek a perzisztencia kontextussal való interakcióra szolgálnak. Az EntityManager API-t arra használjuk, hogy a munkavégzés folyamatában elérjük az adatbázist. Fő feladata, hogy segítségével elmentsük az entitásainkat az adatbázisba (perzisztáció), töröljük az entitásainkat az adatbázisból. E mellett természetesen meg is kereshetünk bizonyos entitásokat elsődleges kulcs alapján, vagy valamilyen lekérdezést hajtsunk végre és az összes entitás egy halmazát kapjuk vissza. Ez az interfész hasonló a Hibernate-ben található Session-höz.

Két fő típusa a konténer által menedzselt Entity Manager és az alkalmazás által menedzselt Entity Manager.

Konténer által menedzselt Entity Manager[szerkesztés]

A legszélesebb körben a Java EE környezet által felkínált EJB konténerben való használata terjedt el. Ebben a módban a konténer felelős az Entity Manager megnyitásáért és bezárásáért (és ez persze az alkalmazás számára transzparens módon történik). Ezzel egyetemben a tranzakció határokért is felelős. Egy ilyen konténer által menedzselt EM az alkalmazás számára JNDI lookup vagy injektálás útján válik elérhetővé. Az ilyen EM megköveteli a JTA tranzakciók használatát.

EM elérése függőség injektálás révén[szerkesztés]

@PersistenceContext
 public EntityManager em;

Megjegyzés: A @PersistenceContext annotáció csak session típusú Bean-ekben, Servletekben és JSP-ben használható.

Egy EM JNDI Lookup-ja[szerkesztés]

@Stateless
@PersistenceContext(name="ProjectEM", unitName="Project")
public class ProjectSessionBean implements Project {

    @Resource
    SessionContext ctx;
 
    public void makeCurrent() {
         try {
            EntityManager em = (EntityManager)ctx.lookup("ProjectEM");
         }catch(Exception e){
                       e.printStackTrace();
         }
    }
}

Alkalmazás által menedzselt Entity Manager[szerkesztés]

A Java SE környezetben nem a konténer, hanem maga az alkalmazás kezeli az Entity Manager életciklusát. Az ilyen EM-t az EntityManagerFactory osztály createEntityManager metódusával lehet létrehozni. Egy EntityManagerFactory betöltéséhez használni kell a javax.persistence.Persistence osztályt, amint azt az alábbi példa is mutatja:

public class Employee {
 
     public static void main(String[] args) {
         EntityManagerFactory emf =
             Persistence.createEntityManagerFactory("EmpService");
         EntityManager em = emf.createEntityManager();
     ...
         em.close();
         emf.close();
 }

Fontos megjegyezni, hogy az EM-t és a hozzá tartozó factory-t kézzel kell lezárnunk!

Nem csak Java SE, hanem Java EE környezetben is használhatók az alkalmazás által kezelt Entity Manager-ek. Ezek létrehozásához a @PersistenceUnit annotációt kell használni, ami egy referenciát deklarál a perzisztencia egységhez tartozó EntityManagerFactory-hoz, lásd. az alább példát:

@PersistenceUnit
 EntityManagerFactory emf;

Alapműveletek[1][szerkesztés]

Az Entity Manager legalapvetőbb műveletei közé tartoznak a persist, find és a remove. Ez a fejezet ezeket mutatja be néhány egyszerű lekérdezéssel karöltve.

Entitás perzisztálása (persist metódus)[szerkesztés]

A persist metódus egy új entitás példányt ad hozzá a perzisztencia kontextushoz, ezzel ütemezi annak adatbázisba való beillesztését is. A következő kódrészlet bemutatja a persist metódus használatát egy egyszerű példán:

// új entitás példány beállítása
Employee employee = new Employee(10);
employee.setName("Miller");
employee.setSalary(70000);
// innentől kezdve az entity manager kezelje
em.persist(employee);
// továbbra is lehetséges módosítani az adaton
em.setSalary(75000);

Először létrehozunk egy szokványos Java objektumpéldányt az Employee osztályból. A persist metódus meghívásával az objektum az Entity Manager fennhatósága alá került, és egészen addig ő fogja kezelni, amíg a perzisztencia kontextus véget nem ér (általában ez a tranzakció vége). Mindaddig, amíg ez be nem következik továbbra is módosíthatunk az entitás adatain, és biztosak lehetünk benne, hogy commit után az adatbázisban az objektum legutolsó állapota lesz jelen.

Entitás keresése az elsődleges kulcsa alapján (find metódus)[szerkesztés]

Egy gyakori feladat JPA alapú alkalmazások esetén, hogy meg kell keresni bizonyos entitásokat az adatbázisban. Mivel az elsődleges kulcs egyértelműen meghatározza az egyes entitásokat, így ezt használhatjuk, amennyiben ismerjük az értékét.

Employee employee = em.find(Employee.class, Integer.valueOf(10));
if (employee != null) {
// do something
}

A find metódus visszaadja a megadott elsődleges kulccsal rendelkező entitást vagy egy null referenciát, ha nem talált a feltételnek megfelelő entitást. Ennek megfelelően érdemes a find használata után az eredmény null-al való egyezőségét megvizsgálni mielőtt azt használnánk!

Entitás törlése (remove metódus)[szerkesztés]

A remove metódus segítségével egy létező entitást törölhetünk az adatbázisból. Ez a törlendő entitás referenciáját várja paraméterként, de fontos, hogy ez az entitás már menedzselve kell hogy legyen az EM által! Például:

// get a managed entity
Employee employee = em.find(Employee.class, Integer.valueOf(10));
if (employee != null) {
em.remove(employee);
}

Alapvető lekérdezések[szerkesztés]

A find metódussal lekérhetünk egy entitást az elsődleges kulcsa alapján, ami kényelmes és sokszor használt technika, azonban ez sok alkalmazás esetén nem elég. Gyakran az entitásokat az adataik alapján szeretnénk keresni, ehhez azonban valamilyen keresési feltételt kell megadnunk. A Java Persistence Query Language (JPQL) pontosan erre szolgál.

JPQL példák[szerkesztés]

A JPQL lekérdezések kísértetiesen hasonlítanak az SQL lekérdezésekre. A legfőbb különbség az, hogy a lekérdezések nem adatbázis táblákra vonatkoznak, hanem az alkalmazás entitásaira. Tekintsük a következő lekérdezést, amely kiválasztja az Employee osztály összes példányát:

SELECT e FROM Employee e

A FROM részben azt állítjuk, hogy az Employee típusból szeretnénk választani, és ennek egy e azonosítót adunk (amivel később hivatkozhatunk rá). A SELECT részben megmondjuk, hogy az e típusú elemeket szeretnénk lekérni, így ennek a lekérdezésnek az eredménye Employee-kből álló lista lesz. Amennyiben szűkíteni szeretnénk a keresési találatokat olyan elemekre, amelyek bizonyos keresési feltételeknek megfelelnek, akkor adjunk hozzá a lekérdezéshez egy WHERE feltételt. Ez ismét hasonló az SQL-es WHERE-hez, de az entitásokra és azok adattagjaira Java módon hivatkozunk. Például az Employee osztályunk egy lastName perzisztens adattagot. Ha csak a megadott lastName értékkel rendelkező alkalmazottakat szeretnénk lekérni, akkor egy ilyen lekérdezést használjunk:

SELECT e FROM Employee e WHERE e.lastName = 'Miller'

Ha szeretnénk paraméteres lekérdezéseket készíteni, például az előbbi esetben a paraméterben megadott lastName-nek megfelelő alkalmazottakat kigyűjteni, akkor használjuk a következő (vagy hasonló) lekérdezést:

SELECT e FROM Employee e WHERE e.lastName = :name

Lekérdezések típusai[szerkesztés]

Kétféle JPQL lekérdezést használhatunk az alkalmazásunkban. Az egyik a statikus lekérdezés, amikor annak minden tagját fordítási időben ismerjük és előre meg tudjuk írni, a másik pedig a dinamikus, amikor futásidőben megadott paraméternek megfelelően kell bizonyos lekérdezéseket végrehajtani. Most csak az utóbbira térünk ki. Dinamikus lekérdezések létrehozására az Entity Manager createQuery metódusa szolgál, amely paraméterként a végrehajtandó JPQL lekérdezés szövegét várja. Például:

String selectFrom = "SELECT e FROM Employee e";
String whereClause = getWhereClause();
Query query = em.createQuery(selectFrom + whereClause);

Lekérdezések futtatása[szerkesztés]

Az előző pontban kapott Query objektummal több mindent kezdhetünk. Amennyiben paraméteres JPQL lekérdezést adtunk meg, úgy meg kell adni a paraméterek aktuális értékét a lekérdezés végrehajtása előtt. Erre használható a Query objektum setParameter metódusa. Az összeállított lekérdezést végül a getResultList metódus meghívásával tudjuk lefuttatni, ami visszaadja a lekérdezés eredményét (ami egy lista lesz).

Query query = em.createNamedQuery("findEmployeeByLastName");
query.setParameter("name", "Miller");
List result = query.getResultList();

Mindez rövidebben:

List result = em.createNamedQuery("findEmployeeByLastName")
		.setParameter("name", "Miller")
		.getResultList();

Egy hosszabb példa[szerkesztés]

Egy @Stateful annotációval ellátott Bean osztály[szerkesztés]

import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import java.util.List;

@Stateful(name = "Movies")
public class MoviesImpl implements Movies {

    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    public void addMovie(Movie movie) throws Exception {
        entityManager.persist(movie);
    }

    public void deleteMovie(Movie movie) throws Exception {
        entityManager.remove(movie);
    }

    public List<Movie> getMovies() throws Exception {
        Query query = entityManager.createQuery("SELECT m from Movie as m");
        return query.getResultList();
    }

}

A hozzá tartozó entitás Bean[szerkesztés]

import javax.persistence.Entity;

@Entity
public class Movie {

    private String director;
    private String title;
    private int year;

    public Movie() {
    }

    public Movie(String director, String title, int year) {
        this.director = director;
        this.title = title;
        this.year = year;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }
}

Külső hivatkozások[szerkesztés]

Jegyzetek[szerkesztés]

  1. Sabine Heider: Basics of the Java Persistence API – Understanding the Entity Manager. [2010. november 27-i dátummal az eredetiből archiválva]. (Hozzáférés: 2011. április 29.)