简体   繁体   English

Hibernate:CRUD Generic DAO

[英]Hibernate: CRUD Generic DAO

My web application has got a lot of service tables/entities, such as payment_methods , tax_codes , province_codes , etc. 我的Web应用程序有很多服务表/实体,例如payment_methodstax_codesprovince_codes等。

Each time I add a new entity, I have to write a DAO. 每次我添加一个新实体,我都要写一个DAO。 The thing is that, basically, they are all the same, but the only difference is the entity class itself . 问题是,基本上,它们都是一样的,但唯一的区别是实体类本身

I know that Hibernate tools can generate the code for me automatically but I can't use them now (don't ask why) so I'm thinking of a Generic DAO . 我知道Hibernate工具可以自动为我生成代码,但我现在不能使用它们(不要问为什么)所以我在考虑使用Generic DAO There's a lot of literature about that but I can't put pieces together and make it work with Spring. 有很多关于这方面的文献,但我不能把它们放在一起,让它与Spring一起工作。

It's all about generics I think, it will have four basic methods: 我认为这是关于泛型的,它将有四种基本方法:

  • listAll
  • saveOrUpdate
  • deleteById
  • getById

and that's all. 就这样。


Question: 题:

What's the best practice for not re-inventing the wheel? 不重新发明车轮的最佳做法是什么? Isn't there something ready to use, yet? 是不是有东西可以使用了呢?

here's mine 这是我的

@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

and you can then access like so in service layer: 然后您可以在服务层中进行访问:

 @Autowired
    private Dao dao;

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

Spring Data JPA is a wonderful project that generate DAOs for you, and more! Spring Data JPA是一个很棒的项目,可以为您生成DAO等等! You only have to create an interface (without any implementation): 您只需要创建一个接口(没有任何实现):

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {}

This interface (via inherited JpaRepository ) will automatically give you: 这个接口(通过继承的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);

The interface is strongly typed (generics) and automatically implemented for you. 界面是强类型(泛型)并自动为您实现。 For every entity all you have to do is to create an interface extending JpaRepository<T,Integer extends Serializable> . 对于每个实体,您所要做的就是创建一个扩展JpaRepository<T,Integer extends Serializable>的接口。

But wait, there's more! 但等等,还有更多! Assuming your PaymentMethod has name and validSince persistent fields. 假设您的PaymentMethod具有namevalidSince持久字段。 If you add the following method to your interface: 如果您将以下方法添加到您的界面:

interface PaymentMethodsDao extends JpaRepository<PaymentMethods, Integer> {

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

}

the framework will parse the method name: 框架将解析方法名称:

findBy ( Name like) And ( ValidSince greater than) findBy名字喜欢) AndValidSince大于)

create the JPA QL query, apply paging and sorting ( Pageable page ) and run it for you. 创建JPA QL查询,应用分页和排序(可分页Pageable page )并为您运行它。 No implementation needed: 无需实施:

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

Resulting query: 结果查询:

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

And with paging applied. 并应用分页。

The only downside is that the project is rather new and it is relatively easy to hit buts (but it is very actively developed). 唯一的缺点是该项目相当新,而且相对容易受到影响(但它非常积极地开发)。

you can use Generic DAO as leverage for other Domain specific DAO classes. 您可以使用Generic DAO作为其他Domain特定DAO类的杠杆。 Suppose you have an Employee Domain class as: 假设您有一个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;
    }


}

then the required generic DAO would look something like this: 然后所需的通用DAO看起来像这样:

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

Generic DAO implementation: 通用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);
}
} 

This generic DAO class then needs to be extended by every Domain specific DAO class. 然后,需要通过每个特定于域的DAO类来扩展此通用DAO类。 The Domain specific DAO class may even implement another interface for operations that are not common in general. 特定于域的DAO类甚至可以为通常不常见的操作实现另一个接口。 And prefer sending type information using constructor. 并且更喜欢使用构造函数发送类型信息。

Do not write specific dao for each entity. 不要为每个实体编写特定的dao。 You can implement one generic DAO that does 90% of work for all entities you need. 您可以实现一个通用DAO,它可以为您需要的所有实体执行90%的工作。 You can extend it in cases you want specific treatment of certain entities. 您可以在需要特定处理某些实体的情况下扩展它。

In project I am currently working on we have such DAO that wraps Hibernate session providing methods similar to those that you described. 在我正在开发的项目中,我们有这样的DAO,它包含Hibernate会话,提供类似于你描述的方法。 Moreover we are using ISearch API - the open source project hosted at google code and providing very convenient criteria building interface for Hibernate and JPA. 此外,我们正在使用ISearch API - 在Google代码中托管的开源项目,并为Hibernate和JPA提供了非常方便的标准构建界面。

you can create a baseDAO Interface and a baseDAO implementation class. 您可以创建baseDAO接口和baseDAO实现类。 And When you need specific use case with different class types you can just create that class's DAO which inherit baseDAO class and implement extra interface with that class's specific needs like this 当你需要具有不同类类型的特定用例时,你可以创建该类的DAO,它继承了baseDAO类并实现了该类特定需求的额外接口,如下所示

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

}

and specific interface 和具体的界面

public interface IUserDAO extends IBaseDAO<User> {

   public User getUserById(long userId);

   public User findUserByUsername(String username);

}

and classes like this 和这样的课程

@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