2016-06-26 73 views
5

Ho trovato alcuni tutorial su come creare un DAO Hibernate con generici, ma tutti usano EntityManager anziché SessionFactory. La mia domanda è come costruire un DAO con generici usando SessionFactory. Ho il seguito finora:Come implementare Hobernate DAO con generici

Interfaccia:

public interface GenericDao<T> { 

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

Classe:

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

io sono sicuro di come fare per findById utilizzando farmaci generici. Credo che gli altri metodi siano giusti, ma correggimi se sbaglio.

DOMANDA LATERALE: L'utilizzo di EntityManager è più vantaggioso rispetto all'utilizzo di SessionFactory? Ho visto alcuni post sull'argomento, ma vorrei qualche altra opinione.

+0

In Java, i generici vengono implementati dalla cancellazione e il parametro di tipo formale 'T' diventa' Oggetto' in fase di esecuzione. In altre parole, in fase di esecuzione, il tipo "T" non esiste. Qualsiasi metodo generico che restituisca un'istanza 'T' appena coniata richiederà quindi un token di tipo run time che il metodo può utilizzare per determinare in modo riflessivo il tipo di istanza che dovrà creare. Una firma più pratica per 'findById (...)' è quindi 'public T findById (classe class, long id)'. – scottb

+0

@scottb quindi verrà utilizzato il token Classe per determinare quale tipo di oggetto deve essere restituito dal metodo? Come potrei fare esattamente questo?Con gli esempi di 'EntityManager', ho visto' entityManager.find (type.class, id); 'ma non sono sicuro di come farlo con' SessionFactory'. –

+0

Se il tipo che è necessario restituire ha un costruttore senza argomenti, allora il modo più semplice per dinamicamente una nuova istanza di un tipo arbitrario 'T' sarebbe utilizzare il metodo' newInstance() 'di' Classe ', per esempio. 'T myObj = class.newInstance();'. In caso contrario, potrebbe essere necessario utilizzare la riflessione tramite l'oggetto 'Classe ' per richiamare un costruttore appropriato con argomenti. In tale metodo, 'class' in' Classe class' ha il ruolo di un token * di tipo run time *. In Java, a volte sono necessari proprio perché i tipi generici non esistono in fase di esecuzione. – scottb

risposta

5

È necessario accedere allo Class<T> da tale metodo. Hai due opzioni, è possibile passare l'Class<T> nel metodo:

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

Oppure si può passare il Class<T> nel costruttore della classe per l'uso nel metodo:

@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 
    } 
} 

e sottoclassi passerebbe la loro classe in superclasse:

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

Quindi, utilizzando l'istanza clazz è possibile ottenere l'entità nel vostro metodo generico utilizzando il Session#get metodo:

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

vedere le seguenti domande per ulteriori informazioni:


Per quanto riguarda la domanda lato, la EntityManager fa parte della JPA (il Ja va API Persistenza). Lo sviluppo dell'applicazione utilizzando le specifiche dell'API Java invece dell'API di Hibernate consente alla tua applicazione di non diventare dipendente da Hibernate. Ciò consente di passare da implementazioni JPA popolari come Hibernate, OpenJPA o TopLink senza apportare modifiche al codice.

This question ha ulteriori informazioni sulla differenza.

+0

Grazie! Un'altra domanda a parte - C'è un motivo per usare 'EntityManager' su' SessionFactory' e viceversa? O entrambi fanno principalmente la stessa cosa? –

+0

Non è necessario aggiungere la riga 'super (User.class);'. La classe generica astratta può trovare l'argomento tipo delle sue classi per bambini, come visto qui: https://github.com/acdcjunior/acdcjunior-github-io-example-projects/blob/master/spring-mvc-jpa-mockito -piloto/src/main/java/net/acdcjunior/piloto/infrastruttura/jpa/JpaAbstractRepository.java # L43 – acdcjunior

+0

@JakeMiller 'EntityManager' è JPA,' SessionFactory' è Hibernate (un'implementazione JPA). Non sono la stessa cosa. 'EntityManager' (JPA) è per' Session' (Hibernate) come 'EntityManagerFactory' (JPA) è per' SessionFactory' (Hibernate). Di solito, preferiamo JPA. Ma se non si prevede di cambiare l'implementazione da Hibernate ad altri (come TopLink), non dovrebbe avere importanza (voglio dire, in questo caso, usare quello che preferisci). – acdcjunior