如何构建jpql查询哪个搜索条件是对象的多个属性?

时间:2012-05-23 09:13:26

标签: jpa

我有问题通过JPA查询数据库。有例外:

org.hibernate.QueryParameterException: Position beyond number of declared ordinal parameters. Remember that ordinal parameters are 1-based! Position: 1
    at org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterDescriptor(ParameterMetadata.java:80)
    at org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterExpectedType(ParameterMetadata.java:86)
    at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:444)
    at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:416)
    at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:440)
    at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:67)
    at com.lawa.service.impl.SubjectServiceImpl.getTotal(SubjectServiceImpl.java:746)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

我的代码是:

@Transactional(propagation=Propagation.REQUIRED)
    public long getTotal(PSubject search) {
        StringBuilder jsql = new StringBuilder("select count(*) from PSubject p where p.id=p.id ");
        ArrayList paramValues  = new ArrayList();
        if(search.getName()!=null && search.getName().trim().length()>0) {
            jsql.append(" and p.name=:name");
            paramValues.add(search.getName().trim());
        }
        if(search.getType()!=null && search.getType().trim().length()>0) {
            jsql.append(" and p.type=:type");
            paramValues.add(search.getType().trim());
        }
        if(search.getMacaddress()!=null && search.getMacaddress().trim().length()>0) {
            jsql.append(" and p.macaddress=:macaddress");
            paramValues.add(search.getMacaddress().trim());
        }
        if(search.getUri()!=null && search.getUri().trim().length()>0) {
            jsql.append(" and p.uri=:uri");
            paramValues.add(search.getUri().trim());
        }
        if(search.getDescription()!=null && search.getDescription().trim().length()>0) {
            jsql.append(" and p.description=:description");
            paramValues.add(search.getDescription().trim());
        }
        if(search.getCreateTime()!=null) {
            jsql.append(" and p.createTime=:createTime");
        }
        Query query = persistService.getEntityManager().createQuery(jsql.toString());
        for(int i=0;i<paramValues.size();i++) {
            query.setParameter((i+1), paramValues.get(i));
        }
        if(search.getCreateTime()!=null) {
            query.setParameter(":createTime",search.getCreateTime(),TemporalType.DATE);
        }
        Long count = (Long)query.getSingleResult();
        return count;
    }

首先,我想让代码工作,我不喜欢代码。我觉得它不干净,我必须逐个验证“PSubject”的每个属性并联系jpql,我必须选择“createTime”,因为它的类型是“Date”。更重要的是,我将“p.id = p.id”添加到jpql中,这让我感觉不舒服。

请帮我解决异常并给出最佳做法。

2 个答案:

答案 0 :(得分:1)

如果使用命名参数,则应按名称绑定它们:

query.setParameter("macaddress", theMacAddress);

所以你应该使用Map来保存参数值,并按名称索引。

但是这种动态查询正是JPA标准API设计的原因。你应该使用它。

答案 1 :(得分:1)

您应该使用Criteria而不是Query。 它非常适合这个用例。