CDI DAO vs EJB DAO

0

Witam,
Jak wiadomo w czasach JEE5 najczęściej stosowano DAO oparte o EJB. W dzisiejszych czasach pojawiają się opinie, że DAO warto realizować przez CDI, a cały projekt trzymać w archiwum .war, niekoniecznie .ear.

Osobiście jestem zwolennikiem DAO opartym o EJB ponieważ:

  • jest trywialne, a IDE doskonale wspiera tworzenie tego typu obiektów
  • działa out-of-the-box
  • doskonale wspierane również w JEE7
  • posiadanie kilku projektów składających się na ear jest wygodne, ponieważ dzięki temu kompozycja projektu jest lepsza (trochę jak z tworzeniem różnych pakietów do klas, które niekoniecznie są ze sobą związane)

Poza tym:

  • w DAO EJB mam dostęp do timer service out-of-box
  • łatwo mogę udostępniać interfejsy zdalne
  • dependency injection jest trywialne (podobnie jak w CDI)

Pytania:

  1. Jakie są główne przyczyny zainteresowania ludzi DAO opartym o CDI?
  2. Jakie są zalety projektu .war nad projektem .ear?

Pozdrawiam,

0

Które IDE wspiera generację DAO?
Entity = DTO to słyszałem, ale DAO?

0

@vpiotr: NetBeans od dość dawna dość dobrze sobie z tym radzi. Generalnie wszystko opiera się o abstrakcyjny CRUD, który mniej więcej wygląda tak (autogenerated):

public abstract class AbstractFacade<T> {
    private final Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().
                getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}

Generalnie nie ma większych problemów, a wygląda to tak:

  1. Entity Classes From DataBase (tu z reguły trzeba swoje dopasować np. sequences. aby autoincrement sensownie działał).
  2. Session Beans For Entity Classes (opcjonalnie do wyboru interfejsy - które osobiście wole mieć niż nie mieć - zdalne / i lub lokalne). Oczywiście jest to tylko wstęp, większość metod i tak musi być mocno customowa. I tak mechanizm ten oszczędza mnóstwo czasu, refaktoryzuje się to znacznie szybciej niż pisze od początku.

@Koziolek:
Nigdy nie spotkałem się aby klasy @Entity miały w sobie logikę (co najwyżej jakieś adnotacje @PostUpdate, @NamedQueries, ale na pewno nie metody odpowiednie dla DAO). Czy ktoś tego używa w ten sposób w praktycznych projektach?

0

Pracowałem przy projekcie pewnego systemu do banku gdzie logika była w encjach na zasadzie

@Entity
class Tabela{

public Set<Tabela> getTabelaListBasedOnDateBeetween(Date start, Date end, EntityManager em){
    ///blablabla
}
}

takze....

0

@Maro1234 Moim zdaniem EntityManager zawsze powinien być przekazywany przed deprendency injection, ale w projekcie nad którym pracuje spotkałem się z perwersją polegająca na przekazywaniu EntityManagera jako parametru funkcji w zwyklym Session Beanie. IMO krzywe, zrefaktoryzowałem. Nie podoba mi się to ponieważ nie ma tu widocznego rozdzielania aplikacji na warstwy.

0

@NiktWażny nazywa się to to active record chociażby. Poza tym encja z bogatą logiką pozwala na napisanie kodu:

pies.nakarm(kiełbasa, 2);

a nie

pies.getWnętrzności().getŻołądek().setKiełbasa(2);

Generalnie anemiczne klasy (takei tylko z setterami i getterami) to zło > http://en.wikipedia.org/wiki/Anemic_domain_model

0

@Koziolek: dzieki za zwrocenie uwagi, bo dosc inaczej na to patrzylem (musze sie zastanowic nad tym anti-patternem i nad sensowoscia active record, bo nie mam na ten temat zdania). Dla mnie dosc wygodny jest nastepujacy podzial:

piesDao.nakarmPsa(pies, kielbasa, 2);

Dzieki DAO wiem, ze jest to operacja na bazie danych i mam pewien staly interfejs, ktory definiuje mi pewna operacje niezaleznie od jej implementacji. Implementacje zawsze moge wymienic na czytelniejsza, a klienta i tak to nie obchodzi poniewaz korzysta on z interfejsu.

1

Inaczej. Zamiast DAO nazwij to opiekunPsa. Niech będzie sobie interfejsem. Wtedy czy to jest operacja na bazie danych, webservicach czy fizyczna (pytanie jak wyglądala by implementacja białkowa w tym przypadku) nie ma znaczenia. Nazywa się to to ładnie przypadkiem użycia i jest bardzo fajnym podejściem gdy tworzysz kod, bo zamya pewną spójną logikę biznesową w jednym miejscu.

0

Moim zdaniem piesDao nie powinno mieć metody nakarmPsa, bo nie jest ona zwiazana z operacją na bazie danych. Ale powinien być pewien serwis piesService który ma takie metody i przekazuje ich wykonanie do dao.

0

Mniej więcej tak staram się projektować swoje usługi tzn. jedna funkcjonalność z punktu widzenia użytkownika (przypadek użycia) to jeden interfejs. Nie tak czesto logika byla jednak w samych encjach, chociaz zdarzalo sie i tylko wtedy, gdy nie wymagalo to operacji na bazie tylko na samej encji.

W typowym DAO oprócz wywołania edit, create, remove dodatkowo umieszczam jeszcze metody pobierające na różny sposób daną encję (coś jak różne SELECTy w zależności od tego co jest potrzebne, bo z findAll nie korzysta sie zbyt czesto). Często inne, bardziej wyrafinowane usługi wołają DAO (dependency injection). Dzieki temu mam duzo wzglednie malych klas, a kazda sluzy do czego innego (staram sie, aby nie robic obiektow do wszystkiego, bo sa ciezkie w utrzymaniu).

A tak wracajac do tematu czy CDI ma cos co czyni je lepszym od EJB jako obiekt DAO? Moim zdaniem nie ma to wiekszego znaczenia, poniewaz jedne i drugie typy beanow sa transakcyjne.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0