Přeskočit na hlavní obsah

DAO pattern + generika pro EJB3

Když jsem se dostal do fáze většího poznávání J2EE, došlo mi, že vrstvení logiky je nedílnou součástí úspěchu při návrhu.
Jistě by nebylo moudré nechat "dolování dat" rozházené po aplikační logice tak, jak ho zrovna potřebuji. Zde nastupuje DAO (Data Access Object), což je návrhový vzor sloužící ke komunikaci mezi persistentní vrstvou a zbytkem světa.

Asi nejvíce mě zaujala možnost, kde DAO vrstvu definuji pomocí generiky a abstraktní třídy. Více než tisíc slov je lepší přímá ukázka kódu.

První věcí je interface, který obsahuje všechny důležité metody, které je třeba pro DAO jednotlivých entit třeba vystavit:
public interface GenericDAO {
public T find(ID id);
public List findAll();
public T create(T entity);
public T save(T entity);
public void remove(T entity);
}

Jednotlivé metody jsou vcelku jasné. Jedná se o základní operace jako: získej data, vytvoř, ulož, smaž. Co se týče generických typů, jedná se o entitu, které přísluší dané DAO a o typ primárního klíče. Typem primárního klíče může být jak základní datový typ jako String, Integer, tak i složený primární klíč, např: ZakazkaPK (obsahuje číslo zakázky a datum vystavení).

Nyní mohu přejít k vlastní implementaci lokálního interface:
@Local
public interface ZamestnanecDAOLocal extends GenericDAO {
}

Samotná EJB beana může vypadat následovně:
@Stateless
public class ZamestnanecDAOBean implements ZamestnanecDAOLocal {
@PersistenceContext(unitName = "myDB")
private EntityManager em;
//... implementace metod
}


Velkou nevýhodou je ovšem fakt, že pokaždé musím implementovat metody, které jsou potřeba ke splnění požadavku z GenericDAO.

Zde nastupuje abstraktní třída, která za nás vyřeší onu potřebnou implementaci.
public abstract class AbstractDAO implements GenericDAO {
private Class entityBeanType;
private EntityManager em;
public AbstractDAO() {
// vytvari, ziskava typ entity pro dane DAO
this.entityBeanType = (Class) ((ParameterizedType)
getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}

public Class getEntityBeanType() {
return entityBeanType;
}

@PersistenceContext(unitName = "default")
public void setEntityManager(EntityManager em) {
this.em = em;
}

protected EntityManager getEntityManager() {
if (em == null) {
throw new IllegalStateException("...");
}
return em;
}

public T find(ID id) {
T entity;
entity = getEntityManager().find(getEntityBeanType(), id);
return entity;
}

// ... implementace zbylych metod
}


Nyní stačí danou abstraktní třídu nechat dědit samotnou implementací EJB beany:
@Stateless
public class ZamestnanecDAOBean extends AbstractDAO implements ZamestnanecDAOLocal {
}


Takto definovaná beana je schopna podědit abstraktní třídu a například anotovaný setter pro entitymanager převzít na svá bedra. Podle specifikace je totiž možné EJB beany nechat dědit mezi sebou, s vyjímkou, že dependency injections a další služby jsou poté managovány potomkem, v našem případě "ZamestnanecDAOBean".

Aby samotné DAO nebylo tak chudé, přidal jsem si několik dalších možností. Některé jsou již specifikovány na danou implementace ORM frameworku. Osobně jsem díky tomu přešel na Hibernate Session a Criteria API.
Tady jsou některé další metody:

/**
*

Vraci vsechny zaznamy z dane tabulky, ktera prislusi entite.
* Navic umoznuje definovat razeni podle Hibernate Criteria API: Order


*

Zpusob pouziti: {@code findAll(Order.asc("jmeno"), Order.desc("prijmeni"))}


*
* @param orderBy definice razeni zaznamu
* @return vsechny zaznamy, pokud zadne neexistuji, vraci null
*/
public List findAll(Order... orderBy);

/**
*

Vraci vsechny zaznamy z dane tabulky, ktera prislusi entite.
* Navic umoznuje definovat omezeny vyber dat, pouzivane napr. pro strankovani.


*

Zpusob pouziti: {@code findAll(0, 20); } Prvni radek je roven 0


*
* @param first prvni radek, od ktereho se vybiraji zaznamy
* @param offset maximalni pocet vybiranych zaznamu
* @return vsechny zaznamy dle definovanych omezenich
*/
public List findAll(int first, int offset);

/**
*

Vraci vsechny zaznamy z dane tabulky, ktera prislusi entite.
* Navic umoznuje definovat omezeny vyber dat, pouzivane napr. pro strankovani
* a definovat razeni podle Hibernate Criteria API: Order


*

Zpusob pouziti: {@code findAll(0, 20, Order.asc("jmeno")); } Prvni radek je roven 0


*
* @param first prvni radek, od ktereho se vybiraji zaznamy
* @param offset maximalni pocet vybiranych zaznamu
* @param orderBy definice razeni zaznamu
*
* @return vsechny zaznamy dle definovanych omezenich
*/
public List findAll(int first, int offset, Order... orderBy);

/**
*

Dohledava zaznamy na zaklade Hibernate Example.


*

Spousti: {@code findByExample(exampleInstance, false, false, false, excludeProperty)}


*

Zpusob pouziti: 15.6. Example queries
*
* @param exampleInstance s naplnenymi vlastnostmi pro vyber
* @param excludeProperty pradavajici vlastnosti pro vyber pres example
* @return dohledane zaznamy
*/
public List findByExample(T exampleInstance, String... excludeProperty);

/**
*

Ziskava pocet vsech radku z tabulky prislusici dane entite


*
* @return pocet vsech radku
*/
public int countAll();

Komentáře

  1. Drive jsem neco podobneho pouzival pro vsechny DAO objekty, ale to vede k castemu poruseni DRY (don`t repeat yourself). Pokud ma entita mit pouze CRUD operace, tak je lepsi udelat tovranu, ktera pro danou entitu vrati zakladni DAO pouze s CRUD operacemi. Neco podobneho ma myslim JBoss Seam a rikaji tomu EntityHome.


    GenericDao dao = GenericDaoFactory.get(MyEntity.class);
    MyEntity entity = dao.find(id);

    OdpovědětVymazat
  2. Asi to z toho kontextu uplne nevypadlo, ale dalsim krokem jsou implementace specialnich metod vztahujici se k dane entite. Pr:
    public interface ZamestnanecDAOLocal extends GenericDAO {
    public List findByTyp(int typ);
    public List findByStredisko(String cisloStrediska);
    ....
    }

    V kazdem pripade pro ciste CRUD operace souhlasim s tim DAO Factory.
    Jinak Seam skutecne neco takoveho ma, zajimave je, ze se jedna v podstate jen o nadefinovani metadat k dane entite a Seam sam vygeneruje CRUD aplikaci. Existuje i moznost s Hibernate Search.
    Me osobne to ovsem prislo prilis velke vazani se na Seam. Mam navic jeste vzdaleneho klienta na stejnou business logiku, cimz je pro me vrstveni docela dulezite.

    OdpovědětVymazat
  3. zde je DAO vrstva tvorena EJB? zajimave, ja vzdy pouzival POJO a AbstractFactory pattern

    OdpovědětVymazat
  4. to kooudy: Presnejsi popis tohoto vzoru muzes naleznout na strankach hibernate.

    http://www.hibernate.org/328.html

    Pro pouziti na EJB, pod nazvem: "Writing DAOs as managed EJB 3.0 components"

    OdpovědětVymazat

Okomentovat

Populární příspěvky z tohoto blogu

Jak si v IT vydělat hodně peněz?

Na začátek by bylo dobré, abych objasnil samotný titulek, který může na někoho působit jako červený hadr. Článek nebude o obecných pravidlech, ale bude vyprávět můj vlastní příběh, na kterém vám zkusím ukázat, jak se dá docílit úspěchu, či alespoň správně nastartovat svojí vlastní kariéru v IT.

I když se z názvu článku dá dedukovat, že se vše bude točit kolem peněz, není tomu tak. Alespoň ze dvou třetin určitě ne. Ale to už předbíhám, pojďme to raději vzít hezky popořadě...

Kdybychom měli mluvit o roce 2017 jako o přelomové době, nejspíše to nebude pravda. I když pro někoho to může být rok plný úspěchů a štěstí v podobě narození zdravých dětí, svatby či první velké lásky, tak z pohledu lidstva se jedná o rok, který jen kopíruje předešlé a v oblasti technologií nás posouvá stejným tempem jako rok předtím.

Jsem naprosto přesvědčen o tom, že i když se současná doba tak nenazývá, tak prožíváme dobu, která jednou bude označena za revoluční, a to zejména díky vynálezu internetu, který je s…

Jak by se firmy neměly chovat k programátorům?

Každý, kdo pracuje v IT oboru, se jistě již setkal s různými „geniálními nápady“, od kterých si firma slibovala zlepšení produktivity či snížení nákladů. Ať už je to zavedení agilních principů, striktní kontrola práce či zavedení nové a skvělé metodiky, o které si „šéf“ přečetl včera na internetu. Jsou z toho skutečně tak nadšení i samotní vývojáři? A bude nový nápad fungovat?
K napsání tohoto článku mě navedly různé programátorské diskuze, kde si lidé stěžovali na firmu, kde pracují. Příklady, které zde uvedu, jsou z reálné praxe. Ať už jsem je zažil jako řadový programátor, či jako šéf týmu.
I když je poptávka po programátorech tak vysoká, že Vás headhunteři nahánějí i ve chvílích, kdy o to opravdu nestojíte, tak i přes to je mnoho lidí, kteří se bojí opustit svoje současné zaměstnání.
Čeho se nejčastěji bojíme? Je to samozřejmě nejistota, kterou si často omlouváme větami jako: „Tady mám své pohodlí, co když to jinde mít nebudu?“ nebo „I když mě to v práci štve a nebaví, tak mě ale…

Jak jsem technologicky postavil startup

Tento příběh pojednává o technologiích, nástrojích a vůbec o všem, co jsem potřeboval k tomu, abych byl schopen, postavit startup na zelené louce.

Každý správný příběh začíná stejně: "Jednou jsem...."

Kapitola první: Nápad
Jednou jsem se setkal s člověkem, který měl nápad na produkt, který se v průmyslu zatím nevyskytuje. I přes prvotní skepsi, kdy jsem si říkal: "Tohle už přeci dávno v průmyslu existuje, ne?", jsem došel ke zjištění, že nikoli.

Tím jsem se dostal ke svému prvnímu poučení. Průmysl je technologicky dost zabržděný. Osobně se domnívám, že těch důvodů, proč tomu tak je, je několik. Za prvé je to fakt, že většina lidí, kteří se pohybují v tomto odvětví jsou často konzervativní a za správné považují pouze léty osvědčené věci. Druhým důvodem je to, že jakákoli změna znamená riziko. Ať už z pohledu finanční ztráty tak i z pohledu stability výroby. No a třetím a nejzásadnějším důvodem je to, že ač zde máme spousty technologických vymožeností, narážíme na to,…