JPA2 Abstract DAO, Criteria Query & the “like” Operator

16 Jun
2010

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

Avatar

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.

Comment Form

top