So, After a 10+ year break I'm coming back to Java and trying out stuff with JPA and Java generics. I've created a generics based findAll(other) JPA query that basically does
SELECT * FROM source WHERE other_id = other.id;
This is where I'm up to. It works, but I'm wondering if there's a better, cleaner way to do it. Using ManagedType was hard, and there's not much complete documentation or simple examples around.
I've decided to keep my code as generic as possible (no pun intended) so I use JPA2.
This is the root of all Entity Classes. I probably don't need it, but it stops me from having basic mistakes.
import java.io.Serializable;
public abstract class DomainObject implements Serializable {
private static final long serialVersionUID = 1L;
public abstract void setId(Long id);
public abstract Long getId();
}
This is the abstract DAO class. I extend this for the implementation classes as I need to be more specific doing other activities - mostly making sure lazy sets are loaded.
public abstract class GenericDAOImpl implements GenericDAO {
private Class type;
@PersistenceContext
protected EntityManager entityManager;
public GenericDAOImpl(Class type) {
super();
this.type = type;
}
... save and delete classes go here
@Override
public List findAll(T2 where) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(type);
Root rootQuery = criteriaQuery.from(type);
if (where != null) {
EntityType entity = entityManager.getMetamodel().entity(type);
SingularAttribute super T, ?> attribute = null;
for (SingularAttribute super T, ?> singleAttribute: entity.getSingularAttributes()) {
// loop through all attributes that match this class
if (singleAttribute.getJavaType().equals(where.getClass())) {
// winner!
attribute = singleAttribute;
break;
}
}
// where t.object = object.getID()
criteriaQuery.where(criteriaBuilder.equal(rootQuery.get(attribute), where));
}
criteriaQuery.select(rootQuery);
TypedQuery query = entityManager.createQuery(criteriaQuery);
// need this to make sure we have a clean list?
// entityManager.clear();
return query.getResultList();
}
Any suggestions? If anything, I want this out there so other people can make use of it.
解决方案
Hat tip to Adam Bien if you don't want to use createQuery with a String and want type safety:
@PersistenceContext
EntityManager em;
public List allEntries() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(ConfigurationEntry.class);
Root rootEntry = cq.from(ConfigurationEntry.class);
CriteriaQuery all = cq.select(rootEntry);
TypedQuery allQuery = em.createQuery(all);
return allQuery.getResultList();
}