All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.genericdao.dao.hibernate.HibernateBaseDAO Maven / Gradle / Ivy

The newest version!
/* Copyright 2013 David Wolverton
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.genericdao.dao.hibernate;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.NonUniqueResultException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;

import com.googlecode.genericdao.search.ExampleOptions;
import com.googlecode.genericdao.search.Filter;
import com.googlecode.genericdao.search.ISearch;
import com.googlecode.genericdao.search.SearchResult;
import com.googlecode.genericdao.search.hibernate.HibernateMetadataUtil;
import com.googlecode.genericdao.search.hibernate.HibernateSearchProcessor;

/**
 * Base class for DAOs that uses Hibernate SessionFactory and HQL for searches.
 * This is the heart of Hibernate Generic DAO.
 * 
 * @author dwolverton
 * 
 */
@SuppressWarnings("unchecked")
public class HibernateBaseDAO {

	private HibernateSearchProcessor searchProcessor;

	private SessionFactory sessionFactory;

	private HibernateMetadataUtil metadataUtil;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
		searchProcessor = HibernateSearchProcessor.getInstanceForSessionFactory(sessionFactory);
		metadataUtil = HibernateMetadataUtil.getInstanceForSessionFactory(sessionFactory);
	}

	protected SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * Get the current Hibernate session
	 */
	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * Get the instance of HibernateMetadataUtil associated with the session
	 * factory
	 */
	protected HibernateMetadataUtil getMetadataUtil() {
		return metadataUtil;
	}

	/**
	 * Get the instance of EJBSearchProcessor associated with the session
	 * factory
	 */
	protected HibernateSearchProcessor getSearchProcessor() {
		return searchProcessor;
	}

	/**
	 * 

* Persist the given transient instance and add it to the datastore, first * assigning a generated identifier. (Or using the current value of the * identifier property if the assigned generator is used.) This operation * cascades to associated instances if the association is mapped with * cascade="save-update". * *

* This is different from persist() in that it does guarantee * that the object will be assigned an identifier immediately. With * save() a call is made to the datastore immediately if the id * is generated by the datastore so that the id can be determined. With * persist this call may not occur until flush time. * * @return The id of the newly saved entity. */ protected Serializable _save(Object entity) { return getSession().save(entity); } /** * Persist the given transient instances and add them to the datastore, * first assigning a generated identifier. (Or using the current value of * the identifier property if the assigned generator is used.) This * operation cascades to associated instances if the association is mapped * with cascade="save-update". */ protected void _save(Object... entities) { for (Object entity : entities) { _save(entity); } } /** *

* Calls Hibernate's saveOrUpdate(), which behaves as follows: * *

* Either save() or update() based on the * following rules *

    *
  • if the object is already persistent in this session, do nothing *
  • * if another object associated with the session has the same identifier, * throw an exception *
  • if the object has no identifier property, save() it *
  • if the object's identifier has the value assigned to a newly * instantiated object, save() it *
  • if the object is versioned (by a <version> or * <timestamp>), and the version property value is the same value * assigned to a newly instantiated object, save() it *
  • otherwise update() the object *
*/ protected void _saveOrUpdate(Object entity) { getSession().saveOrUpdate(entity); } /** *

* If an entity already exists in the datastore with the same id, call * _update and return false (not new). If no such entity exists in the * datastore, call _save() and return true (new) * * @return true if _save(); false if _update(). */ protected boolean _saveOrUpdateIsNew(Object entity) { if (entity == null) throw new IllegalArgumentException("attempt to saveOrUpdate with null entity"); Serializable id = getMetadataUtil().getId(entity); if (getSession().contains(entity)) return false; if (id == null || (new Long(0)).equals(id) || !_exists(entity)) { _save(entity); return true; } else { _update(entity); return false; } } /** * Either save() or update() each entity, * depending on whether or not an entity with the same id already exists in * the datastore. * * @return an boolean array corresponding to to the input list of entities. * Each element is true if the corresponding entity was * _save()d or false if it was * _update()d. */ protected boolean[] _saveOrUpdateIsNew(Object... entities) { Boolean[] exists = new Boolean[entities.length]; // if an entity is contained in the session, it exists; if it has no id, // it does not exist for (int i = 0; i < entities.length; i++) { if (entities[i] == null) { throw new IllegalArgumentException("attempt to saveOrUpdate with null entity"); } if (getSession().contains(entities[i])) { exists[i] = true; } else { Serializable id = getMetadataUtil().getId(entities[i]); if (id == null || (new Long(0)).equals(id)) { exists[i] = false; } } } // if it has an id and is not contained in the session, it may exist Map, List> mayExist = new HashMap, List>(); for (int i = 0; i < entities.length; i++) { if (exists[i] == null) { Class entityClass = metadataUtil.getUnproxiedClass(entities[i]); //Get the real entity class List l = mayExist.get(entityClass); if (l == null) { l = new ArrayList(); mayExist.put(entityClass, l); } l.add(i); } } // for each type of entity, do a batch call to the datastore to see // which of the entities of that class exist for (Map.Entry, List> entry : mayExist.entrySet()) { Serializable[] ids = new Serializable[entry.getValue().size()]; for (int i = 0; i < ids.length; i++) { ids[i] = getMetadataUtil().getId(entities[entry.getValue().get(i)]); } boolean exists2[] = _exists(entry.getKey(), ids); for (int i = 0; i < ids.length; i++) { exists[entry.getValue().get(i)] = exists2[i]; } } boolean[] isNew = new boolean[entities.length]; // now that we know which ones exist, save or update each. for (int i = 0; i < entities.length; i++) { if (entities[i] != null) { if (exists[i]) { _update(entities[i]); isNew[i] = false; } else { _save(entities[i]); isNew[i] = true; } } } return isNew; } /** *

* Make a transient instance persistent and add it to the datastore. This * operation cascades to associated instances if the association is mapped * with cascade="persist". Throws an error if the entity already exists. * *

* This is different from save() in that it does not guarantee * that the object will be assigned an identifier immediately. With * save() a call is made to the datastore immediately if the id * is generated by the datastore so that the id can be determined. With * persist this call may not occur until flush time. */ protected void _persist(Object... entities) { for (Object entity : entities) { getSession().persist(entity); } } /** * Remove the entity of the specified class with the specified id from the * datastore. * * @return true if the object is found in the datastore and * deleted, false if the item is not found. */ protected boolean _deleteById(Class type, Serializable id) { if (id != null) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class Object entity = getSession().get(type, id); if (entity != null) { getSession().delete(entity); return true; } } return false; } /** * Remove all the entities of the given type from the datastore that have * one of these ids. */ protected void _deleteById(Class type, Serializable... ids) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class Criteria c = getSession().createCriteria(type); c.add(Restrictions.in("id", ids)); for (Object entity : c.list()) { getSession().delete(entity); } } /** * Remove the specified entity from the datastore. * * @return true if the object is found in the datastore and * removed, false if the item is not found. */ protected boolean _deleteEntity(Object entity) { if (entity != null) { Serializable id = getMetadataUtil().getId(entity); if (id != null) { entity = getSession().get(metadataUtil.getUnproxiedClass(entity), id); if (entity != null) { getSession().delete(entity); return true; } } } return false; } /** * Remove the specified entities from the datastore. */ protected void _deleteEntities(Object... entities) { for (Object entity : entities) { if (entity != null) getSession().delete(entity); } } /** * Return the persistent instance of the given entity class with the given * identifier, or null if there is no such persistent instance. * get() always hits the database immediately. */ protected T _get(Class type, Serializable id) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class return (T) getSession().get(type, id); } /** *

* Return the all the persistent instances of the given entity class with * the given identifiers. An array of entities is returned that matches the * same order of the ids listed in the call. For each entity that is not * found in the datastore, a null will be inserted in its place in the * return array. * *

* get() always hits the database immediately. */ protected T[] _get(Class type, Serializable... ids) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class Criteria c = getSession().createCriteria(type); c.add(Restrictions.in("id", ids)); Object[] retVal = (Object[]) Array.newInstance(type, ids.length); for (Object entity : c.list()) { Serializable id = getMetadataUtil().getId(entity); for (int i = 0; i < ids.length; i++) { if (id.equals(ids[i])) { retVal[i] = entity; break; } } } return (T[]) retVal; } /** *

* Return the persistent instance of the given entity class with the given * identifier, assuming that the instance exists. Throw an unrecoverable * exception if there is no matching database row. * *

* If the class is mapped with a proxy, load() just returns an * uninitialized proxy and does not actually hit the database until you * invoke a method of the proxy. This behaviour is very useful if you wish * to create an association to an object without actually loading it from * the database. It also allows multiple instances to be loaded as a batch * if batch-size is defined for the class mapping. */ protected T _load(Class type, Serializable id) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class return (T) getSession().load(type, id); } /** *

* Return the persistent instance of the given entity class with the given * identifier, assuming that the instance exists. Throw an unrecoverable * exception if there is no matching database row. An array of entities is * returned that matches the same order of the ids listed in the call. For * each entity that is not found in the datastore, a null will be inserted * in its place in the return array. * * @see #_load(Class, Serializable) */ protected T[] _load(Class type, Serializable... ids) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class Object[] retVal = (Object[]) Array.newInstance(type, ids.length); for (int i = 0; i < ids.length; i++) { if (ids[i] != null) retVal[i] = _load(type, ids[i]); } return (T[]) retVal; } /** * Read the persistent state associated with the given identifier into the * given transient instance. Throw an unrecoverable exception if there is no * matching database row. */ protected void _load(Object transientEntity, Serializable id) { getSession().load(transientEntity, id); } /** * Get a list of all the objects of the specified class. */ protected List _all(Class type) { type = metadataUtil.getUnproxiedClass(type); //Get the real entity class return getSession().createCriteria(type).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list(); } /** *

* Update the persistent instance with the identifier of the given detached * instance. If there is a persistent instance with the same identifier, an * exception is thrown. This operation cascades to associated instances if * the association is mapped with cascade="save-update". * *

* The difference between update() and merge() is * significant: update() will make the given object persistent * and throw and error if another object with the same ID is already * persistent in the Session. merge() doesn't care if another * object is already persistent, but it also doesn't make the given object * persistent; it just copies over the values to the datastore. */ protected void _update(Object... transientEntities) { for (Object entity : transientEntities) { getSession().update(entity); } } /** *

* Copy the state of the given object onto the persistent object with the * same identifier. If there is no persistent instance currently associated * with the session, it will be loaded. Return the persistent instance. If * the given instance is unsaved, save a copy of and return it as a newly * persistent instance. The given instance does not become associated with * the session. This operation cascades to associated instances if the * association is mapped with cascade="merge". * *

* The difference between update() and merge() is * significant: update() will make the given object persistent * and throw and error if another object with the same ID is already * persistent in the Session. merge() doesn't care if another * object is already persistent, but it also doesn't make the given object * persistent; it just copies over the values to the datastore. */ protected T _merge(T entity) { return (T) getSession().merge(entity); } /** * Search for objects based on the search parameters in the specified * ISearch object. * * @see ISearch */ protected List _search(ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (search.getSearchClass() == null) throw new NullPointerException("Search class is null."); return getSearchProcessor().search(getSession(), search); } /** * Same as _search(ISearch) except that it uses the specified * search class instead of getting it from the search object. Also, if the search * object has a different search class than what is specified, an exception * is thrown. */ protected List _search(Class searchClass, ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (searchClass == null) throw new NullPointerException("Search class is null."); if (search.getSearchClass() != null && !search.getSearchClass().equals(searchClass)) throw new IllegalArgumentException("Search class does not match expected type: " + searchClass.getName()); return getSearchProcessor().search(getSession(), searchClass, search); } /** * Returns the total number of results that would be returned using the * given ISearch if there were no paging or maxResult limits. * * @see ISearch */ protected int _count(ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (search.getSearchClass() == null) throw new NullPointerException("Search class is null."); return getSearchProcessor().count(getSession(), search); } /** * Same as _count(ISearch) except that it uses the specified * search class instead of getting it from the search object. Also, if the search * object has a different search class than what is specified, an exception * is thrown. */ protected int _count(Class searchClass, ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (searchClass == null) throw new NullPointerException("Search class is null."); if (search.getSearchClass() != null && !search.getSearchClass().equals(searchClass)) throw new IllegalArgumentException("Search class does not match expected type: " + searchClass.getName()); return getSearchProcessor().count(getSession(), searchClass, search); } /** * Returns the number of instances of this class in the datastore. */ protected int _count(Class type) { List counts = getSession().createQuery("select count(_it_) from " + getMetadataUtil().get(type).getEntityName() + " _it_").list(); int sum = 0; for (Object count : counts) { sum += ((Long) count).intValue(); } return sum; } /** * Returns a SearchResult object that includes the list of * results like search() and the total length like * searchLength. * * @see ISearch */ protected SearchResult _searchAndCount(ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (search.getSearchClass() == null) throw new NullPointerException("Search class is null."); return getSearchProcessor().searchAndCount(getSession(), search); } /** * Same as _searchAndCount(ISearch) except that it uses the specified * search class instead of getting it from the search object. Also, if the search * object has a different search class than what is specified, an exception * is thrown. */ protected SearchResult _searchAndCount(Class searchClass, ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (searchClass == null) throw new NullPointerException("Search class is null."); if (search.getSearchClass() != null && !search.getSearchClass().equals(searchClass)) throw new IllegalArgumentException("Search class does not match expected type: " + searchClass.getName()); return getSearchProcessor().searchAndCount(getSession(), searchClass, search); } /** * Search for a single result using the given parameters. */ protected Object _searchUnique(ISearch search) throws NonUniqueResultException { if (search == null) throw new NullPointerException("Search is null."); if (search.getSearchClass() == null) throw new NullPointerException("Search class is null."); return getSearchProcessor().searchUnique(getSession(), search); } /** * Same as _searchUnique(ISearch) except that it uses the specified * search class instead of getting it from the search object. Also, if the search * object has a different search class than what is specified, an exception * is thrown. */ protected Object _searchUnique(Class searchClass, ISearch search) { if (search == null) throw new NullPointerException("Search is null."); if (searchClass == null) throw new NullPointerException("Search class is null."); if (search.getSearchClass() != null && !search.getSearchClass().equals(searchClass)) throw new IllegalArgumentException("Search class does not match expected type: " + searchClass.getName()); return getSearchProcessor().searchUnique(getSession(), searchClass, search); } /** * Returns true if the object is connected to the current hibernate session. */ protected boolean _sessionContains(Object o) { return getSession().contains(o); } /** * Flushes changes in the hibernate cache to the datastore. */ protected void _flush() { getSession().flush(); } /** * Refresh the content of the given entity from the current datastore state. */ protected void _refresh(Object... entities) { for (Object entity : entities) getSession().refresh(entity); } protected boolean _exists(Object entity) { if (getSession().contains(entity)) return true; return _exists(entity.getClass(), getMetadataUtil().getId(entity)); } protected boolean _exists(Class type, Serializable id) { if (type == null) throw new NullPointerException("Type is null."); if (id == null) return false; type = metadataUtil.getUnproxiedClass(type); //Get the real entity class Query query = getSession().createQuery("select id from " + getMetadataUtil().get(type).getEntityName() + " where id = :id"); query.setParameter("id", id); return query.list().size() == 1; } protected boolean[] _exists(Class type, Serializable... ids) { if (type == null) throw new NullPointerException("Type is null."); type = metadataUtil.getUnproxiedClass(type); //Get the real entity class boolean[] ret = new boolean[ids.length]; // we can't use "id in (:ids)" because some databases do not support // this for compound ids. StringBuilder sb = new StringBuilder("select id from " + getMetadataUtil().get(type).getEntityName() + " where"); boolean first = true; for (int i = 0; i < ids.length; i++) { if (first) { first = false; sb.append(" id = :id"); } else { sb.append(" or id = :id"); } sb.append(i); } Query query = getSession().createQuery(sb.toString()); for (int i = 0; i < ids.length; i++) { query.setParameter("id" + i, ids[i]); } for (Serializable id : (List) query.list()) { for (int i = 0; i < ids.length; i++) { if (id.equals(ids[i])) { ret[i] = true; // don't break. the same id could be in the list twice. } } } return ret; } protected Filter _getFilterFromExample(Object example) { return searchProcessor.getFilterFromExample(example); } protected Filter _getFilterFromExample(Object example, ExampleOptions options) { return searchProcessor.getFilterFromExample(example, options); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy