命名查询执行的通用实现
Generic implementation for named queries execution
我正在尝试实现一个泛型 class (GenericDaoImpl<T,E>
),它包含一个执行 NamedQueries (findByNamedQuery(..)
) 的方法。此方法要求一个命名查询名称和一个对象数组(参数)。我必须迭代它们并将这些参数绑定到命名查询。
我无法更改方法签名。
public abstract class GenericDaoImpl<T, E> implements GenericDao<T, E> {
@PersistenceContext(unitName="MyUnit")
protected EntityManager em;
private Class<T> persistentClass;
@SuppressWarnings("unchecked")
public GenericDaoImpl() {
this.persistentClass = getPersistentClass();
}
public void setPersistentClass(Class<T> persistentClass) {
this.persistentClass = persistentClass;
}
public Class<T> getPersistentClass() {
Class<?>[] typeArguments = TypeResolver.resolveRawArguments(GenericDao.class, getClass());
this.persistentClass = (Class<T>) typeArguments[0];
return persistentClass;
}
....
@Transactional
public void save(T entity) {
em.persist(entity);
}
@Transactional
public void update(T entity) {
em.merge(entity);
}
@Transactional
public void delete(E id) {
em.remove(em.find(persistentClass,id));
}
...
public List<T> findByNamedQuery(String queryName, Object... params) {
Query q = this.em.createNamedQuery(queryName,persistentClass);
for(int i =1;i<params.length-1;i++){
q.setParameter(i, params[i]);
}
return (List<T>)q.getResultList();
}
}
现在,给出这个命名查询:
@NamedQuery(name="Office.findByStreetAndCity",query="SELECT o from Office o JOIN o.address a WHERE a.street=:street AND a.city=:city"),
让我们执行方法:
String[] params= {"Mount Eden Road", "London"};
List<Office> offices= dao.findByNamedQuery("Office.findByStreetAndCity", params);
但是失败了:
java.lang.IllegalArgumentException: org.hibernate.QueryException: Not
all named parameters have been set: [city, street] [SELECT o from
Office o JOIN o.address a WHERE a.street=:street AND a.city
=:city]
我对 JPA 不是很熟悉,但我认为这是失败的,因为在 NamedQuery 定义上使用命名参数时我们不能按索引设置参数。
您的假设是正确的,您将两者混为一谈。
您可以继续使用 setParameter("street", "Mount Eden Road")
并将您的签名更改为 public List<T> findByNamedQuery(String queryName, Map<String, Object> params)
或重写您的查询以使用位置参数(从 0 开始):
SELECT o from Office o JOIN o.address a WHERE a.street=? AND a.city=?
for(int i = 0; i < params.length; i++){
q.setParameter(i, params[i]);
}
我正在尝试实现一个泛型 class (GenericDaoImpl<T,E>
),它包含一个执行 NamedQueries (findByNamedQuery(..)
) 的方法。此方法要求一个命名查询名称和一个对象数组(参数)。我必须迭代它们并将这些参数绑定到命名查询。
我无法更改方法签名。
public abstract class GenericDaoImpl<T, E> implements GenericDao<T, E> {
@PersistenceContext(unitName="MyUnit")
protected EntityManager em;
private Class<T> persistentClass;
@SuppressWarnings("unchecked")
public GenericDaoImpl() {
this.persistentClass = getPersistentClass();
}
public void setPersistentClass(Class<T> persistentClass) {
this.persistentClass = persistentClass;
}
public Class<T> getPersistentClass() {
Class<?>[] typeArguments = TypeResolver.resolveRawArguments(GenericDao.class, getClass());
this.persistentClass = (Class<T>) typeArguments[0];
return persistentClass;
}
....
@Transactional
public void save(T entity) {
em.persist(entity);
}
@Transactional
public void update(T entity) {
em.merge(entity);
}
@Transactional
public void delete(E id) {
em.remove(em.find(persistentClass,id));
}
...
public List<T> findByNamedQuery(String queryName, Object... params) {
Query q = this.em.createNamedQuery(queryName,persistentClass);
for(int i =1;i<params.length-1;i++){
q.setParameter(i, params[i]);
}
return (List<T>)q.getResultList();
}
}
现在,给出这个命名查询:
@NamedQuery(name="Office.findByStreetAndCity",query="SELECT o from Office o JOIN o.address a WHERE a.street=:street AND a.city=:city"),
让我们执行方法:
String[] params= {"Mount Eden Road", "London"};
List<Office> offices= dao.findByNamedQuery("Office.findByStreetAndCity", params);
但是失败了:
java.lang.IllegalArgumentException: org.hibernate.QueryException: Not all named parameters have been set: [city, street] [SELECT o from Office o JOIN o.address a WHERE a.street=:street AND a.city =:city]
我对 JPA 不是很熟悉,但我认为这是失败的,因为在 NamedQuery 定义上使用命名参数时我们不能按索引设置参数。
您的假设是正确的,您将两者混为一谈。
您可以继续使用 setParameter("street", "Mount Eden Road")
并将您的签名更改为 public List<T> findByNamedQuery(String queryName, Map<String, Object> params)
或重写您的查询以使用位置参数(从 0 开始):
SELECT o from Office o JOIN o.address a WHERE a.street=? AND a.city=?
for(int i = 0; i < params.length; i++){
q.setParameter(i, params[i]);
}