For a project at the university, I had to implement an abstract search in an abstract JPA Dao.
Maybe this class comes handy for some of you
package com.dominikdorn.rest.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Dominik Dorn
*/
public class AbstractJpaDao {
@PersistenceContext
protected EntityManager em;
protected Class entityClass;
public Class getEntityClass() {
return entityClass;
}
public void setEntityClass(Class entityClass) {
this.entityClass = entityClass;
}
public AbstractJpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class) genericSuperclass.getActualTypeArguments()[0];
}
public AbstractJpaDao(Class clazz) {
this.entityClass = clazz;
}
public EntityManager getEm() {
return em;
}
public AbstractJpaDao setEm(EntityManager em) {
this.em = em;
return this;
}
@Override
public TYPE persist(TYPE item) {
if (item == null)
throw new PersistenceException("Item may not be null");
em.persist(item);
return item;
}
@Override
public TYPE update(TYPE item) {
if (item == null)
throw new PersistenceException("Item may not be null");
em.merge(item);
return item;
}
@Override
public List getAll() {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
@Override
public TYPE getById(Long id) {
if (id == null || id < 1)
throw new PersistenceException("Id may not be null or negative");
return (TYPE) em.find(entityClass, id);
}
@Override
public void delete(TYPE item) {
if (item == null)
throw new PersistenceException("Item may not be null");
em.remove(em.merge(item));
}
@Override
public List findByAttributes(Map attributes) {
List results;
//set up the Criteria query
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(getEntityClass());
Root foo = cq.from(getEntityClass());
List predicates = new ArrayList();
for(String s : attributes.keySet())
{
if(foo.get(s) != null){
predicates.add(cb.like((Expression) foo.get(s), "%" + attributes.get(s) + "%" ));
}
}
cq.where(predicates.toArray(new Predicate[]{}));
TypedQuery q = em.createQuery(cq);
results = q.getResultList();
return results;
}
}
To instantiate this for an Entity, e.g. “Item”, simply do this
// get an entityManager somewhere here
AbstractJpaDao- dao = new AbstractJpaDao
- ();
dao.setEm(em);
now you can use this Data Access Object for your persistence stuff.
To now search for entities in your DB, you can use the method findByAttributes which takes a map<String,String> and searches for appropriate items.
If your Entity looks like this
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "ITEM_GEN")
@SequenceGenerator(name="ITEM_GEN", allocationSize=25, sequenceName = "item_seq")
private long id;
@Basic
private String name;
@Basic
private String description;
@Basic
private Integer size;
// constructors, getters, setters
you could search for an item which names contain “test” like this
Map attr = new Hashmap();
attr.put("name", "test");
List- results = dao.findByAttributes(attr);
which comes quite handy in my opinion. Also note, that you don’t have to pre-generate your JPA2 Model classes.
1 Response to JPA2 Abstract DAO, Criteria Query & the “like” Operator
Timo Westkämper
August 30th, 2010 at 14:04
Nice approach. If you want a more compact typesafe Query API for JPA, then try out Querydsl : http://source.mysema.com/display/querydsl/Querydsl
Querydsl also supports JDO, Java collections, SQL and Lucene.