命名查询执行的通用实现

时间:2018-12-02 13:29:30

标签: java hibernate jpa named-query

我正在尝试实现一个通用类(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:不   所有已命名的参数均已设置:[城市,街道] [从中选择o   办公室o加入o。在a.street =:street和a.city地址   =:city]

我对JPA不太熟悉,但是我认为这失败了,因为在NamedQuery定义上使用命名参数时,我们无法按索引设置参数。

1 个答案:

答案 0 :(得分:0)

您的假设是正确的,并且您在两者之间混在一起。

您可以继续使用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]);
}