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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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<TYPE> {
    @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<TYPE>) 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<TYPE> 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<TYPE> findByAttributes(Map<String, String> attributes) {
        List<TYPE> results;
        //set up the Criteria query
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<TYPE> cq = cb.createQuery(getEntityClass());
        Root<TYPE> foo = cq.from(getEntityClass());
 
        List<Predicate> predicates = new ArrayList<Predicate>();
        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<TYPE> q = em.createQuery(cq);
 
        results = q.getResultList();
        return results;
    }
}

To instantiate this for an Entity, e.g. “Item”, simply do this

1
2
3
  // get an entityManager somewhere here 
  AbstractJpaDao<Item> dao = new AbstractJpaDao<Item>();
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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

1
2
3
4
 
Map<String,String> attr = new Hashmap<String,String>();
attr.put("name", "test");
List<Item> 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.

2 Responses 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.

Avatar

a friend

February 4th, 2011 at 18:14

I was looking for a way to dynamically add multiple predicates to one criteria query and this was
a very useful example.

Thanks!

Comment Form

top