Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Friday, January 20, 2012

Advanced QBE pattern (common using generics)

On previous post I introduced the QBE pattern.

The pattern saves us a lot of tedious binding code.
However, one still need to implement the same method for each Entity.

To save us the redundant work of defining the same QBE method for each entity, where only the entity is changed, we could utilize Generics.

Using Generics we will implement only one method in a base class, and each concrete QBE (on certain @Entity) will inherit from that base class.


Lets see that in action.

First, we define the interface for the base class:

public interface BaseDAO {

   

    /**
     * Perform a query based on the values in the given object.
     * Each (String) attribute will be searched based on the Like comparison.
     * Comply the QueryByExample (QBE) pattern
     * @param modelEntity The Entity with values to search
     * @param propertiesToExclude Any property which the search will ignored.
     * @return Instances that answer the given parameters values (empty if none)
     */
    public List getByElementsLike(T modelEntity, List propertiesToExclude);   

    /**
     * Perform a query based on the values in the given object.
     * Each attribute will be searched based on the Equality comparison.
     * Comply the QueryByExample (QBE) pattern
     * @param modelEntity The Entity with values to search
     * @param propertiesToExclude Any property which the search will ignored
     * @return Instances that answer the given parameters values (empty if none)
     */
    public List getByElementsEqual(T modelEntity, List propertiesToExclude);

}



 Second step is to write the Base class implementation

public class BaseDaoImpl implements BaseDAO {
//Get DB session access using Spring 3.1 Entity Manger
     @PersistenceContext
    protected EntityManager em;
  
    protected Class entityClass;

   
     //Initialize the entity class
     @SuppressWarnings("unchecked")
    public BaseRepositoryImpl() {
            ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
            this.entityClass = (Class) genericSuperclass.getActualTypeArguments()[0];
        }

    protected Class getEntityClass() {
        return entityClass;
    }   
  

    public List getByElementsLike(T modelEntity,List propertiesToExclude) {

        // get the native hibernate session
        Session session = (Session) em.getDelegate();

        // create an example from our model-entity, exclude all zero valued numeric properties
        Example example = Example.create(modelEntity).excludeZeroes().enableLike(MatchMode.ANYWHERE);

        for (String property : propertiesToExclude) {
            example.excludeProperty(property);
        }       

        // create criteria based on the customer example
        Criteria criteria = session.createCriteria(getEntityClass()).add(example);

        // perform the query       
        return criteria.list();

    }

    public List getByElementsEqual(T modelEntity,List propertiesToExclude) {

        // get the native hibernate session
        Session session = (Session) em.getDelegate();

        // create an example from our customer, exclude all zero valued numeric properties
        Example example = Example.create(modelEntity).excludeZeroes();

        for (String property : propertiesToExclude) {
            example.excludeProperty(property);
        }   

        // create criteria based on the customer example
        Criteria criteria = session.createCriteria(getEntityClass()).add(example);

        // perform the query       
        return criteria.list();
    }

}


Third step is to extend the base class:
@Entity

public class Order{
..
}

 

@Entity
public class Item{
..
}

 
public class OrderDaoImpl extends BaseDaoImpl implements
        BaseDao{

//No need to implement the QBE again here

}

public class ItemDaoImpl extends BaseDaoImpl implements
        BaseDao{

//No need to implement the QBE again here

}


Kindly let me know for any further improvements.

QBE pattern

When writing an enterprise system, there is a common pattern of a user who fill in a search form and get a corresponding result based on the given search parameters.

Handling this request manually in the backend is a bit tedious since for every search parameter, the developer need to check if the user insert a value and if so, concatenate the corresponding string into the WHERE clause in the SQL.

The Query By Example (QBE) pattern is a pattern that helps deal with the mentioned task.

It is implemented by ORM frameworks (such as Hibernate) and also avlaiable as part of possible to implement utilizing the the spec in JPA 2.0 (as seen in OpenJPA project)

The QBE implementation expect the model instance (the object which is annotated with @Entity).
That instance should have the form search values in it.
Than the implementation  framework does all the SQL wiring magic and save us the tedious work.
So at the end we just return the query result.

Lets discuss a case where a user want to query the Order object.

The Order class need to be annotated with @Entity


@Entity
public class Order{
..
}

Using a Hibernate implementation :
public List findByOrderElements(Order order) {

 Session session = getSession();

//Hibernate assembles the query with the given entity to query
 Example example = Example.create(order) //create Example object given the instance to query
     .enableLike(MatchMode.ANYWHERE) //optional parameters
     .excludeZeroes()
     .ignoreCase();

//Get the query result
 List result = session.createCriteria(Order.class)
     .add(example)
     .list();
        
 return result;
}


That's it...

Important note:
  • QBE will only work on one object (won't help in case the form input has properties of other related fields, i.e.  requires join)
  • Version properties, identifiers and associations are ignored (if QBE would consider the id than it would match only one instance...)

For even more advanced stuff regarding QBE pattern, please follow my next post.

Tuesday, August 16, 2011

DAO layer - Generics to the rescue

Generics can be a powerful tool to create reusable code with the power of compile time verification (type safety..).
Unfortunately I feel the main stream developers still afraid of it.
However, in analogy to Hagrid's spiders I would say that Generics are seriously misunderstood creatures... :-)

I hope the following example will demonstrate how useful they can be.

The Problem - DAO (Data Access Objects) classes have common methods such as save, update, delete, loadAll.. which are required in every DAO class.
Writing a base class with these common methods and making every DAO object extend it, is simply not enough since each DAO class represents a different domain class and therefore the type used in the common methods' signature is different (although implementation is similar), for example:
class OrderDAO {
//save method receive an Order
public void save(Order order){....}
//getAll method return Orders List
public List<Order> getAll(){...} 
}

class UserDAO{
//save method receive an User
public void save(User user){....}
//getAll method return Users List
public List<User> getAll(){...}
}


How Generics can help us create a base class with a common implementation and yet, keep method signature type-safety?
First, we need to define an interface with the common methods:
/**
 * Base interface for CRUD operations and common queries
 */
public interface IDaoBase<T> {
	
	public List<T> loadAll();
	
	public void save(T domain);
		
	public void update(T domain);
		
	public void delete(T domain);
	
	public T get(Serializable id);
	
	/**
	 * Get list by criteria
	 * @param detachedCriteria the domain query criteria, include condition and the orders.
	 * @return
	 * 
	 */
	public List<T> getListByCriteria(DetachedCriteria detachedCriteria);
	
	public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size);	
}

Please note that we utilize generics so each method signature has a type T, which in the implemented DAO classes, will be a concrete type, per domain.

The second step is to create an abstract class which implements the common functionality:

public abstract class DaoBase<T> extends HibernateDaoSupport implements IDaoBase<T> {
	private Class<T> entityClass;
	
	@Autowired
	public void setSession(SessionFactory sessionFactory){
		this.setSessionFactory(sessionFactory);
	}
		
	public DaoBase() {
		
		entityClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

        public List<T> loadAll(){
		return getHibernateTemplate().loadAll(entityClass);
	}

	public void delete(T domain) {
		getHibernateTemplate().delete(domain);
	}

	public void save(T domain) {
		getHibernateTemplate().saveOrUpdate(domain);
		
	}

	public void update(T domain) {
		getHibernateTemplate().merge(domain);
	}
	
	
        public T get(Serializable id) {
		T o = (T) getHibernateTemplate().get(entityClass, id);
		return o;
	}

	public List<T> getListByCriteria(DetachedCriteria detachedCriteria,
			int offset, int size) {
		return getHibernateTemplate().findByCriteria(detachedCriteria, offset, size);
	}
	
	public List<T> getListByCriteria(DetachedCriteria detachedCriteria) {
		return getHibernateTemplate().findByCriteria(detachedCriteria);
	}
}

And that's it !
Take a minute or two to inspect how the base object implements a generic functionality with a type-safety manner.

All we have to do when implementing a new DAO is:
1. Interface to extend the IDaoBase with a concrete type
public interface DaoUser extends IDaoBase<User> {//<=Notice the User typing
	//Add any additional custom methods..
	public User getbyUsername(String username);
        public User getbyEmail(String email);
}

2. Implementation to extend the DaoBase with a concrete type

//This class has all the common methods, which are type safe for the User class
@Repository("daoUser")
public class DaoUserImpl extends DaoBase<User> implements DaoUser { //<=Notice the User typing

	public User getbyUsername(String username) {
// concrete implmentation		...
	}

So now you see how powerful it is to use generics. Hope it is now a bit less scary and more understood...

Please post me if you have further cool tricks utilizing generics for ease development.

Moreover, if you think any of the above can be improved, I'll be happy to hear about it.