2016-06-26 48 views
5

Znalazłem kilka samouczków na temat tworzenia DAO Hibernate z generics, ale wszystkie one używają EntityManager zamiast SessionFactory. Moje pytanie brzmi: jak zbudować DAO z generycznymi używającymi SessionFactory. Mam poniżej tej pory:W jaki sposób zaimplementować Hibernate DAO z generics

Interfejs:

public interface GenericDao<T> { 

    public void save(T obj); 
    public void update(T obj); 
    public void delete(T obj); 
    public T findById(long id); 
} 

Klasa:

@Repository 
public class GenericDaoImpl<T> implements GenericDao<T> { 

    @Autowired 
    private SessionFactory sessionFactory; 

    public void save(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.save(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public void update(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.update(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public void delete(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.delete(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public T findById(long id) { 
     // ?? 
     return null; 
    } 

jestem pewien, jak się do tego zabrać findById używając rodzajowych. Wierzę, że inne metody są słuszne, ale popraw mnie, jeśli się mylę.

SIDE PYTANIE: Czy korzystanie EntityManager bardziej korzystny niż przy użyciu SessionFactory? Widziałem kilka postów na ten temat, ale chciałbym jeszcze kilku opinii.

+0

W Javie, generics są realizowane przez wymazanie, a formalny parametr typu "T" staje się "Object" w czasie wykonywania. Innymi słowy, w czasie wykonywania wpisz 'T' nie istnieje. Każda ogólna metoda zwracająca nowo wygenerowaną instancję 'T' będzie zatem wymagać tokena typu działania, którego metoda może użyć do refleksyjnego określenia typu instancji, którą będzie musiał utworzyć. Bardziej praktycznym podpisem dla 'findById (...)' jest zatem 'public T findById (Class class, long id)'. – scottb

+0

@ scottb, aby użyć znacznika Class do określenia typu obiektu, który metoda musi zwrócić? Jak miałbym to dokładnie zrobić?W przykładach 'EntityManager' widziałem' entityManager.find (type.class, id); 'ale nie jestem pewien jak to zrobić z' SessionFactory'. –

+0

Jeśli typ, który chcesz zwrócić, ma konstruktor bezargumentowy, wówczas najłatwiejszym sposobem dynamicznego wybrania nowej instancji dowolnego typu 'T' byłoby użycie metody' newInstance() 'z' klasy ', na przykład. 'T myObj = class.newInstance();'. W przeciwnym razie możesz potrzebować użyć odbicia za pomocą obiektu 'Class ', aby wywołać odpowiedni konstruktor z argumentami. W takiej metodzie "klasa" w klasie "Klasa " pełni rolę tokena * biegu czasu *. W Javie są one czasem konieczne właśnie dlatego, że typy ogólne nie istnieją w czasie wykonywania. – scottb

Odpowiedz

5

Musisz mieć dostęp do Class<T> z tej metody. Masz dwie opcje, można zdać Class<T> do metody:

public T findById(long id, Class<T> clazz) { 
    // method implementation 
} 

Albo można przekazać Class<T> do konstruktora klasy do stosowania w metodzie:

@Repository 
public class GenericDaoImpl<T> implements GenericDao<T> { 

    private Class<T> clazz; 

    protected GenericDaoImpl(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    // other methods omitted 

    public T findById(long id) { 
     // method implementation 
    } 
} 

I podklasy minie ich klasy do klasy bazowej:

public class UserDao extends GenericDaoImpl<User> { 
    public UserDao() { 
     super(User.class); 
    } 
} 

Następnie, używając instancję clazz można uzyskać podmiot w sposób rodzajowy pomocą Session#get metoda:

T entity = session.get(clazz, id); 

zobacz następujące pytania, aby uzyskać więcej informacji:


Jeśli chodzi o pytanie z boku, EntityManager jest częścią JPA (the Ja va Persistence API). Rozwijanie aplikacji przy użyciu specyfikacji Java API zamiast interfejsu Hibernate API pozwala aplikacji nie być zależnym od Hibernate. Pozwala to na przełączanie się między popularnymi implementacjami JPA, takimi jak Hibernate, OpenJPA lub TopLink, bez dokonywania zmian w kodzie.

This question ma więcej informacji na temat różnicy.

+0

Dziękujemy! Inne pytanie: czy istnieje powód, aby używać 'EntityManager' zamiast' SessionFactory' i na odwrót? Czy oboje robią przede wszystkim to samo? –

+0

Nie trzeba dodawać, że linia 'super (User.class);'. Klasa abstrakcyjna generyczna może znaleźć argument typowy dla swoich klas potomnych, jak widać tutaj: https://github.com/acdcjunior/acdcjunior-github-io-example-projects/blob/master/spring-mvc-jpa-mockito -piloto/src/main/java/net/acdcjunior/piloto/infrastructure/jpa/JpaAbstractRepository.java # L43 – acdcjunior

+0

@JakeMiller 'EntityManager' to JPA,' SessionFactory' to Hibernate (implementacja JPA). To nie to samo. 'EntityManager' (JPA) to' Session' (Hibernate), ponieważ 'EntityManagerFactory' (JPA) należy do' SessionFactory' (Hibernate). Zazwyczaj wolimy JPA. Ale jeśli nie planujesz kiedykolwiek zmienić implementacji z Hibernate na inny (np. TopLink), nie powinno to mieć znaczenia (mam na myśli, w tym przypadku, użyj tego, co lubisz). – acdcjunior