Thursday, August 31, 2006

 

Generic CRUD DAO

這是參考Don't repeat the DAO!這篇文章前面一部分的note
單純運用Java 5.0 Generic、Spring、Hibernate
後面還有加入AOP的部份比較複雜
改天我再另外整理

這篇文章的程式碼
為Eclipse Project,需要的library都放好在裡面了,測試請以Unit Test執行PersonDaoTest.java


Generic CRUD DAO

Generic CRUD DAO只需要

GenericDao.java
package genericdao;

import java.io.Serializable;

public interface GenericDao<T, PK extends Serializable> {
   PK create(T newInstance);
   T read(PK id);
   void update(T transientObject);
   void delete(T persistentObject);
}
GenericDaoHibernateImpl.java
package genericdao.impl;

import genericdao.GenericDao;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;

public class GenericDaoHibernateImpl<T, PK extends Serializable> implements GenericDao<T, PK> {
   private SessionFactory sessionFactory;

   private Class<T> type;

   public GenericDaoHibernateImpl(Class<T> type) {
      this.type = type;
   }

   public PK create(T o) {
      return (PK) getSession().save(o);
   }

   public T read(PK id) {
      return (T) getSession().get(type, id);
   }

   public void update(T o) {
      getSession().update(o);
   }

   public void delete(T o) {
      getSession().delete(o);
   }

   public Session getSession() {
      boolean allowCreate = true;
      return SessionFactoryUtils.getSession(sessionFactory, allowCreate);
   }

   public void setSessionFactory(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
   }
}

Your DAO

使用Generic CRUD DAO來寫你自己的CRUD DAO你需要

Person.java (Your Domain Object)
package genericdaotest.domain;

import java.io.Serializable;

public class Person implements Serializable {
   private Long id;

   private String name;

   private Integer weight;

   public Person(String name, Integer weight) {
      this.name = name;
      this.weight = weight;
   }

   // Default constructor needed by Hibernate
   protected Person() {
   }

   public Long getId() {
      return id;
   }

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

   public String getName() {
      return name;
   }

   private void setName(String name) {
      this.name = name;
   }

   public Integer getWeight() {
      return weight;
   }

   public void setWeight(Integer weight) {
      this.weight = weight;
   }
}
Person.hbm.xml (Your Domain Object's Hibernate Mapping)
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="genericdaotest.domain">
   <class name="Person">
      <id name="id">
         <generator class="native"></generator>
      </id>
      <property name="name" update="false" />
      <property name="weight" />
   </class>
</hibernate-mapping>

Use Your DAO

使用你的DAO需要

my-test.xml (Spring Configration File)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<beans>
   <bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName">
         <value>org.hsqldb.jdbcDriver</value>
      </property>
      <property name="url">
         <value>jdbc:hsqldb:file:db/data</value>
      </property>
      <property name="username">
         <value>sa</value>
      </property>
      <property name="password">
         <value></value>
      </property>
   </bean>

   <bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      
      <property name="mappingResources">
         <list>
            <value>genericdaotest/domain/Person.hbm.xml</value>
         </list>
      </property>
      <property name="hibernateProperties">
         <props>
            <prop key="hibernate.dialect">
               org.hibernate.dialect.HSQLDialect
            </prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
         </props>
      </property>
      <property name="dataSource">
         <ref bean="dataSource" />
      </property>
   </bean>

   <bean id="personDao"
      class="genericdao.impl.GenericDaoHibernateImpl">
      <constructor-arg>
         <value>genericdaotest.domain.Person</value>
      </constructor-arg>
      <property name="sessionFactory">
         <ref bean="sessionFactory" />
      </property>
   </bean>
</beans>
PersonDaoTest.java (Codes That Use Your DAO)
package genericdaotest;

import genericdao.GenericDao;
import genericdaotest.domain.Person;
import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class PersonDaoTest extends TestCase {
   private ApplicationContext factory;

   public PersonDaoTest(String s) {
      super(s);
      factory = new ClassPathXmlApplicationContext("my-test.xml");
   }

   public void testCrud() throws Exception {
      // Create
      GenericDao personDao = (GenericDao) factory.getBean("personDao");
      Person createPerson = new Person("Mellqvist", 88);
      personDao.create(createPerson);
      assertNotNull(createPerson.getId());
      Long id = createPerson.getId();

      restartSession();

      // Read
      Person foundPerson = (Person) personDao.read(id);
      assertEquals(createPerson.getWeight(), foundPerson.getWeight());

      restartSession();

      // Update
      Integer updateWeight = 90;
      foundPerson.setWeight(updateWeight);
      personDao.update(foundPerson);
      Person updatedPerson = (Person) personDao.read(id);
      assertEquals(updateWeight, updatedPerson.getWeight());

      restartSession();

      // Delete
      personDao.delete(updatedPerson);
      restartSession();
      assertNull(personDao.read(id));
   }

   protected void setUp() throws Exception {
      openSession();
   }

   protected void tearDown() throws Exception {
      closeSession();
   }

   private void openSession() {
      SessionFactory sessionFactory = getSessionFactory();
      Session session = SessionFactoryUtils.getSession(sessionFactory, true);
      TransactionSynchronizationManager.bindResource(sessionFactory,
            new SessionHolder(session));
   }

   private void closeSession() {
      SessionFactory sessionFactory = getSessionFactory();
      SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
            .unbindResource(sessionFactory);
      sessionHolder.getSession().flush();
      sessionHolder.getSession().close();
      SessionFactoryUtils.releaseSession(sessionHolder.getSession(),
            sessionFactory);
   }

   private void restartSession() {
      closeSession();
      openSession();
   }

   private SessionFactory getSessionFactory() {
      return (SessionFactory) factory.getBean("sessionFactory");
   }
}

Exercise

練習寫一個你自己的DAO看看吧!
還記得需要哪些檔案嗎?
你可以重用:

所以你需要: Try Try看吧!


Comments:
Excellent! exactly what I was looking for. Thank you for blogging this Hibernate example!
 
Post a Comment



<< Home