簡體   English   中英

Hibernate:CRUD Generic DAO

[英]Hibernate: CRUD Generic DAO

我的Web應用程序有很多服務表/實體,例如payment_methodstax_codesprovince_codes等。

每次我添加一個新實體,我都要寫一個DAO。 問題是,基本上,它們都是一樣的,但唯一的區別是實體類本身

我知道Hibernate工具可以自動為我生成代碼,但我現在不能使用它們(不要問為什么)所以我在考慮使用Generic DAO 有很多關於這方面的文獻,但我不能把它們放在一起,讓它與Spring一起工作。

我認為這是關於泛型的,它將有四種基本方法:

  • listAll
  • saveOrUpdate
  • deleteById
  • getById

就這樣。


題:

不重新發明車輪的最佳做法是什么? 是不是有東西可以使用了呢?

這是我的

@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

然后您可以在服務層中進行訪問:

 @Autowired
    private Dao dao;

   @Transactional(readOnly = true)
    public List<MyEntity> getAll() {
      return dao.getAll(MyEntity.class);
    }

Spring Data JPA是一個很棒的項目,可以為您生成DAO等等! 您只需要創建一個接口(沒有任何實現):

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {}

這個接口(通過繼承的JpaRepository )會自動給你:

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);

界面是強類型(泛型)並自動為您實現。 對於每個實體,您所要做的就是創建一個擴展JpaRepository<T,Integer extends Serializable>的接口。

但等等,還有更多! 假設您的PaymentMethod具有namevalidSince持久字段。 如果您將以下方法添加到您的界面:

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {

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

}

框架將解析方法名稱:

findBy名字喜歡) AndValidSince大於)

創建JPA QL查詢,應用分頁和排序(可分頁Pageable page )並為您運行它。 無需實施:

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

結果查詢:

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

並應用分頁。

唯一的缺點是該項目相當新,而且相對容易受到影響(但它非常積極地開發)。

您可以使用Generic DAO作為其他Domain特定DAO類的杠桿。 假設您有一個Employee Domain類:

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


}

然后所需的通用DAO看起來像這樣:

通用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);
}

通用DAO實現:

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

然后,需要通過每個特定於域的DAO類來擴展此通用DAO類。 特定於域的DAO類甚至可以為通常不常見的操作實現另一個接口。 並且更喜歡使用構造函數發送類型信息。

不要為每個實體編寫特定的dao。 您可以實現一個通用DAO,它可以為您需要的所有實體執行90%的工作。 您可以在需要特定處理某些實體的情況下擴展它。

在我正在開發的項目中,我們有這樣的DAO,它包含Hibernate會話,提供類似於你描述的方法。 此外,我們正在使用ISearch API - 在Google代碼中托管的開源項目,並為Hibernate和JPA提供了非常方便的標准構建界面。

您可以創建baseDAO接口和baseDAO實現類。 當你需要具有不同類類型的特定用例時,你可以創建該類的DAO,它繼承了baseDAO類並實現了該類特定需求的額外接口,如下所示

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

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();
}

}

和具體的界面

public interface IUserDAO extends IBaseDAO<User> {

   public User getUserById(long userId);

   public User findUserByUsername(String username);

}

和這樣的課程

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM