Hibernate: CRUD Générique DAO

mon application web a beaucoup de tables/entités de service, comme payment_methods,tax_codes,province_codes, etc.

Chaque fois que j'ajoute une nouvelle entité, je dois écrire un DAO. Le truc, c'est que, fondamentalement, ils sont tous les mêmes, mais la seule différence est l' classe d'entité.

je sais que les outils D'hibernation peuvent générer le code pour moi automatiquement mais je ne peux pas les utiliser maintenant (ne demandez pas pourquoi) donc je pense à un Dao Générique. Il y a un beaucoup de littérature à ce sujet, mais je ne peux pas assembler les morceaux et le faire fonctionner avec le printemps.

Il est tout au sujet des génériques, je pense, il y aura quatre méthodes de base:

  • listAll
  • saveOrUpdate
  • deleteById
  • getById

et c'est tout.


Question:

What is the pour ne pas avoir réinventé la roue? N'est-il pas quelque chose prêt à l'emploi, encore?

35
demandé sur UserNotFoundException 2012-03-15 18:05:21

5 réponses

voici le mien

@Component
public class Dao{

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;

    public <T> T save(final T o){
      return (T) sessionFactory.getCurrentSession().save(o);
    }


    public void delete(final Object object){
      sessionFactory.getCurrentSession().delete(object);
    }

    /***/
    public <T> T get(final Class<T> type, final Long id){
      return (T) sessionFactory.getCurrentSession().get(type, id);
    }

    /***/
    public <T> T merge(final T o)   {
      return (T) sessionFactory.getCurrentSession().merge(o);
    }

    /***/
    public <T> void saveOrUpdate(final T o){
      sessionFactory.getCurrentSession().saveOrUpdate(o);
    }

    public <T> List<T> getAll(final Class<T> type) {
      final Session session = sessionFactory.getCurrentSession();
      final Criteria crit = session.createCriteria(type);
  return crit.list();
    }
// and so on, you shoudl get the idea

et vous pouvez ensuite y accéder comme dans la couche de service:

 @Autowired
    private Dao dao;

   @Transactional(readOnly = true)
    public List<MyEntity> getAll() {
      return dao.getAll(MyEntity.class);
    }
39
répondu NimChimpsky 2012-03-15 14:18:30

Spring Data JPA est un projet merveilleux qui génère des DAOs pour vous, et plus encore! Vous n'avez qu'à créer une interface (sans mise en œuvre):

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {}

cette interface (via hered JpaRepository) vous donnera automatiquement:

PaymentMethod save(PaymentMethod entity);
Iterable<PaymentMethod> save(Iterable<? extends PaymentMethod> entities);
PaymentMethod findOne(Integer id);
boolean exists(Integer id);
Iterable<PaymentMethod> findAll();
long count();
void delete(Integer id);
void delete(PaymentMethod entity);
void delete(Iterable<? extends PaymentMethod> entities);
void deleteAll();
Iterable<PaymentMethod> findAll(Sort sort);
Page<PaymentMethod> findAll(Pageable pageable);
List<PaymentMethod> findAll();
List<PaymentMethod> findAll(Sort sort);
List<PaymentMethod> save(Iterable<? extends PaymentMethods> entities);
void flush();
PaymentMethod saveAndFlush(PaymentMethods entity);
void deleteInBatch(Iterable<PaymentMethods> entities);

l'interface est fortement tapée (generics) et automatiquement implémentée pour vous. Pour chaque entité tout ce que vous avez à faire est de créer une interface d'extension JpaRepository<T,Integer extends Serializable>.

mais attendez, il y a plus! En supposant que votre PaymentMethod a name et validSince champs persistants. Si vous ajoutez la méthode suivante à votre interface:

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {

  Page<PaymentMethod> findByNameLikeAndValidSinceGreaterThan(
    String name, Date validSince, Pageable page
  );

}

le framework analysera le nom de la méthode:

findBy (Nom comme) And ( ValidSince plus grand que)

créer la JPA QL, appliquer la pagination et de tri (Pageable page) et l'exécuter pour vous. Pas de mise en œuvre neededed:

paymentMethodsDao.findByNameLikeAndValidSinceGreaterThan(
  "abc%",
  new Date(),
  new PageRequest(0, 20, Sort.Direction.DESC, "name"
);

requête:

SELECT *  //or COUNT, framework also returns the total number of records
FROM PaymentMethods
WHERE name LIKE "abc%"
  AND validSince > ...

et avec mise en page appliquée.

Le seul inconvénient est que le projet est assez nouveau, et il est relativement facile de frapper buts (mais il est très développées).

25
répondu Tomasz Nurkiewicz 2012-03-15 14:24:26

n'écrivez pas de dao spécifique pour chaque entité. Vous pouvez implémenter un DAO générique qui fait 90% du travail pour toutes les entités dont vous avez besoin. Vous pouvez l'étendre dans les cas où vous voulez un traitement spécifique de certaines entités.

dans le projet je travaille actuellement sur nous avons un tel DAO qui enveloppe session D'hibernation fournissant des méthodes similaires à celles que vous avez décrites. De plus, nous utilisons L'API ISearch - le projet open source hébergé chez Google code et fournissant des critères de construction très pratiques interface pour hibernation et JPA.

4
répondu AlexR 2012-03-15 14:15:48

vous pouvez utiliser Dao générique comme levier pour d'autres classes DAO spécifiques au domaine. Supposons que vous ayez une classe de domaine employé comme:

  @Entity
  @Table(name="employee")
  public class Employee {

    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(name="emp_name")
    private String empName;

    @Column(name="emp_designation")
    private String empDesignation;

    @Column(name="emp_salary")
    private Float empSalary;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public String getEmpDesignation() {
        return empDesignation;
    }

    public void setEmpDesignation(String empDesignation) {
        this.empDesignation = empDesignation;
    }

    public Float getEmpSalary() {
        return empSalary;
    }

    public void setEmpSalary(Float empSalary) {
        this.empSalary = empSalary;
    }


}

alors le DAO Générique requis ressemblerait à quelque chose comme ceci:

Générique Interface DAO:

 public interface GenericRepositoryInterface<T> {

    public T save(T emp);
    public Boolean delete(T emp);
    public T edit(T emp);
    public T find(Long empId);
}

Générique DAO de mise en œuvre:

@Repository
public class GenericRepositoryImplementation<T> implements GenericRepositoryInterface<T> {

protected EntityManager entityManager;
private Class<T> type;

public GenericRepositoryImplementation() {
    // TODO Auto-generated constructor stub

}

public GenericRepositoryImplementation(Class<T> type) {
    // TODO Auto-generated constructor stub

    this.type = type;
}

public EntityManager getEntityManager() {
    return entityManager;
}

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}
@Override
public T save(T emp) {
    // TODO Auto-generated method stub
    entityManager.persist(emp);
    entityManager.flush();
    return emp;
}

@Override
public Boolean delete(T emp) {
    // TODO Auto-generated method stub
    try {
         entityManager.remove(emp);
    } catch (Exception ex) {
        return false;
    }
    return true;
}

@Override
public T edit(T emp) {
    // TODO Auto-generated method stub
    try{
       return entityManager.merge(emp);
    } catch(Exception ex) {
        return null;
    }
}

@Override
public T find(Long empId) {
    // TODO Auto-generated method stub
    return (T) entityManager.find(Employee.class, empId);
}
} 

cette classe DAO générique doit alors être étendue par chaque classe DAO spécifique au domaine. La classe Dao spécifique au domaine peut même implémenter une autre interface pour les opérations qui ne sont pas communes en général. Et préfèrent envoyer des informations de type en utilisant le constructeur.

4
répondu Shahid Yousuf 2018-07-12 16:53:09

vous pouvez créer une Interface baseDAO et une classe d'implémentation baseDAO. Et quand vous avez besoin d'un cas d'utilisation spécifique avec différents types de classe, vous pouvez simplement créer le DAO de cette classe qui hérite de la classe baseDAO et implémenter une interface supplémentaire avec les besoins spécifiques de cette classe comme ceci

IBaseDAO

 public interface IBaseDAO<T> {

/**
 * @Purpose :Save object of type T
 * @param transientInstance
 */
public Object persist(final T transientInstance);

/**
 * @Purpose :Delete object of type T
 * @param persistentInstance
 */
public void remove(final T persistentInstance);

/**
 * @Purpose :Update Object of type T
 * @param detachedInstance
 * @return
 */
public T merge(final T detachedInstance);

/**
 * @Purpose :Find object by 'id' of type T
 * @param identifier
 * @return
 */
public T findById(final Long identifier, Class<?> persistClass);
}

Classe BaseDAO

public class BaseDAO<T> implements IBaseDAO<T> {

@Autowired
private SessionFactory sessionFactory;

public Object persist(T entity) {
    return this.getSession().save(entity);
}

@Override
public void remove(T persistentInstance) {
    this.getSession().delete(persistentInstance);
}

@SuppressWarnings("unchecked")
@Override
public T merge(T detachedInstance) {
    return (T) this.getSession().merge(detachedInstance);
}

@SuppressWarnings("unchecked")
@Override
public T findById(Long identifier, Class<?> persistClass) {
    return (T) this.getSession().get(persistClass, identifier);
}

public SessionFactory getSessionFactory() {
    return sessionFactory;
}

public Session getSession() {
    return getSessionFactory().getCurrentSession();
}

}

et l'interface spécifique

public interface IUserDAO extends IBaseDAO<User> {

   public User getUserById(long userId);

   public User findUserByUsername(String username);

}

et les classes comme ceci

@Repository("userDAO")
public class UserDAO extends BaseDAO<User> implements IUserDAO {

public User getUserById(long userId) {
    return findById(userId, User.class);
}

@Override
    public User findUserByUsername(String username) {
        Criteria criteria = getSession().createCriteria(User.class);
        criteria.add(Restrictions.eq("username", username));
        return (User) criteria.uniqueResult();
    }

}
0
répondu Mandar Kawtakwar 2017-08-25 13:21:50