Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: Adding GenericDAO classes to Spring

  1. #1
    Join Date
    Jul 2005
    Posts
    11

    Default Adding GenericDAO classes to Spring

    Howdi,

    I have just started implementing DAO's using the GenericDAO pattern. More specifically this excellent implementation of the pattern.

    http://www-128.ibm.com/developerwork...enericdao.html

    Seems like an ideal candidate pattern for addition into spring-hibernate3.jar???

    Regards,
    Damon.

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    You already have DAO support inside Spring hibernate package - see the HibernateTemplate class. You can extend it or use HibernateDaoSupport. Note that composition is preferred to inheritance.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Jul 2005
    Posts
    11

    Default

    Hi Costin,
    Thanks for the reply.. Yes, I have used HibernateTemplate for most of my database access code over the past year. ;-)

    The advantage of the GenericDAO pattern is that it virtually eliminates the need to code DAO's for most simple cases.. CRUD methods are implemented by the base class and finder methods are implemented using AOP and Hibernate named queries in the mapping files.

    I implement an IPersonDAO interface that specifies my finder methods. Then I use the SpringProxyFactoryBean as follows targeted to use the GenericDAOImpl class.

    <bean id="personDao"
    class="org.springframework.aop.framework.ProxyFact oryBean">
    <property name="interceptorNames">
    <list>
    <value>finderIntroductionAdvisor</value>
    </list>
    </property>
    <property name="proxyInterfaces">
    <value>persist.PersonDao</value>
    </property>
    <property name="target">
    <bean parent="abstractDaoTarget">
    <constructor-arg>
    <value>domain.Person</value>
    </constructor-arg>
    </bean>
    </property>
    </bean>

    Seems like a great way to develop the data access code. Am I missing any obvious downsides?

    Regards,
    Damon.

  4. #4
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    I'm not aware of any downsides except maybe some minor performance downgrade (compared to the normal implementation). I tend to use introduction when working with third parties code of which I have no control - this does not mean however that the idea is not good.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  5. #5
    Join Date
    May 2006
    Location
    Rome, Italy
    Posts
    13

    Talking

    Hello,
    I have implemented a GenericDao pattern.

    First I tried to make a generic type GenericDao<T>, then I saw that it was even better to have a type with generic methods :-)

    Here it is:

    Code:
    /**
     * @author Alessio Pace
     *
     */
    public class PersistenceManagerHibernate extends HibernateDaoSupport implements PersistenceManager {
    
    	protected Logger logger = Logger.getLogger(PersistenceManager.class.getName());
    	
    	public PersistenceManagerHibernate() {
    		super();
    	}
    
    
    	@SuppressWarnings("unchecked")
    	public <T> List<T> findAll(Class<T> entityClass) throws DataAccessException {
    
    		//getHibernateTemplate().setCacheQueries(true);
    		List<T> results = getHibernateTemplate().loadAll(entityClass);
    		
    		Set<T> set = new HashSet<T>(results);
    		results = new ArrayList<T>(set);
    		return results;
    	}
    
    	
    	@SuppressWarnings("unchecked")
    	public <T> T findById(Class<T> entityClass, Long id) throws DataAccessException {
    	
    		//getHibernateTemplate().setCacheQueries(true);
    		T o = (T) getHibernateTemplate().get(entityClass, id);
    		if(o == null){
    			logger.warn("uh oh, document with id '" + id + "' not found...");
    			throw new ObjectRetrievalFailureException(entityClass, id);
    		}
    		else {
    			return o;
    		}
    	}
    	
    	public <T> void saveOrUpdate(T entity) throws DataAccessException {
    		getHibernateTemplate().saveOrUpdate(entity);
    	}
    
    
    	@SuppressWarnings("unchecked")
    	public <T> T merge(T entity) throws DataAccessException {
    		return (T) getHibernateTemplate().merge(entity);
    	}
    
    
    	public <T> void remove(T entity) throws DataAccessException {
    		getHibernateTemplate().delete(entity);
    	}
    
    	public <T> void removeAll(Class<T> entityClass) throws DataAccessException {
    		getHibernateTemplate().deleteAll(this.findAll(entityClass));
    	}
    
    	@SuppressWarnings("unchecked")
    	public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
    			String queryName, String[] paramNames, Object[] values) throws DataAccessException {
    
    		List<T> results = (List<T>) getHibernateTemplate().findByNamedQueryAndNamedParam(queryName, paramNames, values);
    		return results;
    	}
    
    	public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
    			String queryName, Map<String, ?> params) throws DataAccessException {
    
    		String[] paramNames = new String[params.size()];
    		Object[] values = new Object[params.size()];
    		
    		List<String> keys = new ArrayList<String>(params.keySet());
    		for(int i=0; i<keys.size(); i++){
    			String k = keys.get(i);
    			paramNames[i] = k;
    			values[i] = params.get(k);
    		}
    		
    		return this.findByNamedQueryAndNamedParam(entityClass, queryName, paramNames, values);
    	}
    
    	@SuppressWarnings("unchecked")
    	public <T> List<T> findByNamedParam(Class<T> entityClass, String query,
    			String[] paramNames, Object[] values) throws DataAccessException {
    		
    		List<T> results = (List<T>) getHibernateTemplate().findByNamedParam(query, paramNames, values);
    		return results;
    		
    	}
    
    	@SuppressWarnings("unchecked")
    	public <T> List<T> findByNamedParam(Class<T> entityClass, String query,
    			Map<String, ?> params) throws DataAccessException {
    		
    		String[] paramNames = new String[params.size()];
    		Object[] values = new Object[params.size()];
    		
    		List<String> keys = new ArrayList<String>(params.keySet());
    		for(int i=0; i<keys.size(); i++){
    			String k = keys.get(i);
    			paramNames[i] = k;
    			values[i] = params.get(k);
    		}
    		
    		List<T> results = (List<T>) getHibernateTemplate().findByNamedParam(query, paramNames, values);
    		return results;
    		
    	}
    }
    the class simply implements a PersistenceManager interface with the @Transactional annotation in order to be proxyed and be used by the TransactionManager :-)

    I must thank a lot the author of this blog entry, because I have taken its JPA solution and "ported back" to HibernateTemplate:
    http://blog.diefirma.de/2006-01-10/u...i-with-spring/

    The solution IMHO works like a charm :-)

    regards
    Last edited by puccio; May 22nd, 2006 at 10:54 AM.

  6. #6
    Join Date
    Jul 2005
    Posts
    11

    Default

    Hi Puccio,
    Yes, your implementation looks good too..

    What I suspect will happen over the next few months is that lots of people will implement and begin to use the GenericDAO pattern from one article/blog entry or another around the web. We will see the pattern pop up repeatedly in slightly different forms in different places..

    Thats why I think it would be really neat if the Spring people got together a best practise implementation so people don't end up reinventing the wheel!

    Regards,
    Damon.

  7. #7
    Join Date
    May 2006
    Location
    Rome, Italy
    Posts
    13

    Default

    Hi,
    hibernate is a JPA persistence implementation, and as such (as the other implementations) has an EntityManager API which basically has the same set of CRUD APIs of the generic methods you saw above.

    In the future I would expect to see people (and me among them..) extending JpaTemplate, as they did up to now extending the HibernateTemplate, and delegating then to such JpaTemplate generic methods:
    http://static.springframework.org/sp...aTemplate.html

    So I think with JPA (or JDO) coming more and more spread there is not such a need of a "custom" class, the generics are already in, you just have to wrap those classes with yours (anyway, you can also use the EntityManager directly).

    Hope I was helpful :-)
    regards

  8. #8
    Join Date
    Jul 2005
    Posts
    11

    Default

    What I am trying to achieve is to have my service classes use a consistent PersistenceManager interface for CRUD methods. And I want to extend this common interface with my own finder methods for each DAO.

    You seem to be suggesting that my service classes could use this interface directly? Sounds like a good plan!
    http://www.hibernate.org/hib_docs/ej...tyManager.html

    However, it seems that a common requirement would be to add my own finder methods..

    public interface PersonDAO extends EntityManager {
    public Person findPersonByHairColour(String hairColour);
    }

    Then I would need a generic PersistenceManagerImpl as you have outlined to delegate through to the EntityManagerImpl or JPATemplate.

    It seems to me that the need for a custom IPersonDAO interface leads to the need for a generic PersistenceManagerImpl that composes calls to the persistence engine. If this logic follows wouldn't it be better that Spring provided that generic persistence manager wrapper class than everyone coding their own?

    I notice Spring is advertising this pattern on its homepage... ;-)
    http://www.springframework.org/node/278


    Regards,
    Damon.

  9. #9
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    Quote Originally Posted by damonrand
    Howdi,

    I have just started implementing DAO's using the GenericDAO pattern. More specifically this excellent implementation of the pattern.

    http://www-128.ibm.com/developerwork...enericdao.html

    Seems like an ideal candidate pattern for addition into spring-hibernate3.jar???

    Regards,
    Damon.
    Actually even last year I attached to a JIRA issue a somewhat similar (but not taken to the same level) basic generic DAO. I was thinking about checking some code into Spring itself, but it doesn't make much sense. What methods are actually appropriate in the DAO, and what would their names be? i.e. is it save or create? is it load or read?

    So I think this is better left as an example, with people able to create a base DAO that is appropriate for them...

    Regards,
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  10. #10
    Join Date
    May 2006
    Location
    Rome, Italy
    Posts
    13

    Default

    The GenericDao or PersistenceManager with generic methods, as I outlined, are just for basic CRUD operations.

    If you want something more particular, like "User findUserByName(User u)", you can use NamedQueries instead of adding custom methods or subclassing the interface

    I annotated each model entity (i.e. User) with the most commonly used named queries, and I added a method on the PersistenceManager interface which then delegates to HibernateTemplate.findByNameQuery.

    So imagine you have a User entity with a name:
    Code:
    @Entity
    @NamedQueries(value={@NamedQuery(name="user.byName", query="select u from User u where u.name = :name")})
    public class User {
        // ....
        // private String name;
        // ...
    }
    and on the class extending HibernateTemplate there is this method to be used for named queries:
    Code:
    @SuppressWarnings("unchecked")
    	public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
    			String queryName, String[] paramNames, Object[] values) throws DataAccessException {
    
    		List<T> results = (List<T>) getHibernateTemplate().findByNamedQueryAndNamedParam(queryName, paramNames, values);
    		return results;
    	}
    So you may call:
    Code:
    List<User> usersByName = persistenceManager.findByNamedQueryAndNamedParam(User.class, "user.byName", new String[]{"name"}, new String[]{"your value here"});
    Let me know if you need some more explanations.
    regards

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •