简体   繁体   中英

Hibernate : org.hibernate.QueryParameterException: could not locate named parameter

I am working on a Spring-MVC application in which I would like to run a search on multiple variables at the same time. But the code keeps failing at setting parameter for the first value itself. I have no idea why. Any help would be nice.

ListStudents :

@Override
public List<Student> addHostSearchHistory(HostSearchHistory hostSearchHistory, Long hostId) {
    session = this.sessionFactory.getCurrentSession();
    Host host = (Host) session.get(Host.class,hostId);
    host.getHostSearchHistorySet().add(hostSearchHistory);
    hostSearchHistory.setHsHistory(host);
    session.save(hostSearchHistory);
    session.flush();

    StringBuilder sb = new StringBuilder();
    sb.append("from Student as s where ");

    if(!(hostSearchHistory.getCountry()==null)){
        sb.append("s.studentCountry=:").append(hostSearchHistory.getCountry());
    }
    if(!(hostSearchHistory.getCity()==null)){
        sb.append(" OR s.city=:").append(hostSearchHistory.getCity());
    }
    if(!(hostSearchHistory.getDrivingLicense()==null)){
        sb.append(" OR s.studentInfoDetails.drivingLicense=").append(hostSearchHistory.getDrivingLicense());
    }
    if(!(hostSearchHistory.getGender()==null)){
        sb.append(" OR s.gender=").append(hostSearchHistory.getGender());
    }
    if(!(hostSearchHistory.getMotherTongue()==null)){
        sb.append(" OR s.studentInfoDetails.motherTongue=:").append(hostSearchHistory.getMotherTongue());
    }
    if(!(hostSearchHistory.getSmoker()==null)){
        sb.append(" OR s.studentInfoDetails.smoker=").append(hostSearchHistory.getSmoker());
    }
    if(!(hostSearchHistory.getPreviousAuPair()==null)){
        sb.append(" OR s.studentInfoDetails.previouslyAuPair=").append(hostSearchHistory.getPreviousAuPair());
    }
    if(!(hostSearchHistory.getWillingToWork()==null)){
        sb.append(" OR s.studentInfoDetails.willingToWork=").append(hostSearchHistory.getWillingToWork());
    }
    if(!(hostSearchHistory.getWorkForSingleParent()==null)){
        sb.append(" OR s.studentInfoDetails.workForSingleParent=").append(hostSearchHistory.getWorkForSingleParent());
    }
    if(!(hostSearchHistory.getWorkingForDisabledChild()==null)){
        sb.append(" OR s.studentInfoDetails.workingForDisabledChild=").append(hostSearchHistory.getWorkingForDisabledChild());
    }
    if(!(hostSearchHistory.getOtherLanguages()==null)){
        sb.append(" OR s.studentInfoDetails.otherLanguages=:").append(hostSearchHistory.getOtherLanguages());
    }

    sb.append(" order by s.registrationDate desc");

    System.out.println("Sb.toString is "+sb.toString());

    Query query = session.createQuery(sb.toString());

// The code fails here
    if(!(hostSearchHistory.getCountry()==null)){
        query.setParameter("studentCountry",hostSearchHistory.getCountry());
    }
    if(!(hostSearchHistory.getCity()==null)){
        query.setParameter("city",hostSearchHistory.getCity());
    }
    if(!(hostSearchHistory.getDrivingLicense()==null)){
        query.setParameter("drivingLicense",hostSearchHistory.getDrivingLicense());
    }
    if(!(hostSearchHistory.getGender()==null)){
        query.setParameter("gender",hostSearchHistory.getGender());
    }
    if(!(hostSearchHistory.getMotherTongue()==null)){
        query.setParameter("motherTongue",hostSearchHistory.getMotherTongue());
    }
    if(!(hostSearchHistory.getSmoker()==null)){
        query.setParameter("smoker",hostSearchHistory.getSmoker());
    }
    if(!(hostSearchHistory.getPreviousAuPair()==null)){
        query.setParameter("previouslyAuPair",hostSearchHistory.getPreviousAuPair());
    }
    if(!(hostSearchHistory.getWillingToWork()==null)){
        query.setParameter("willingToWork",hostSearchHistory.getWillingToWork());
    }
    if(!(hostSearchHistory.getWorkForSingleParent()==null)){
        query.setParameter("workForSingleParent",hostSearchHistory.getWorkForSingleParent());
    }
    if(!(hostSearchHistory.getWorkingForDisabledChild()==null)){
        query.setParameter("workingForDisabledChild",hostSearchHistory.getWorkingForDisabledChild());
    }
    if(!(hostSearchHistory.getOtherLanguages()==null)){
        query.setParameter("otherLanguages",hostSearchHistory.getOtherLanguages());
    }

    List<Student> studentList = query.list();
    for(Student student : studentList){
        System.out.println("Student name is "+student.getUsername());
    }
   return studentList;

}

Output of sb.toString() :

Sb.toString is from Student as s where s.studentCountry=:Germany OR s.city=:Hamburg OR s.studentInfoDetails.drivingLicense=true OR s.gender=male OR s.studentInfoDetails.smoker=true OR s.studentInfoDetails.willingToWork=true OR s.studentInfoDetails.workingForDisabledChild=true order by s.registrationDate desc

Error log :

org.hibernate.QueryParameterException: could not locate named parameter [studentCountry]
    org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:148)
    org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:165)
    org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:523)
    org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:493)
    com.journaldev.spring.dao.HostSearchHistoryDAOImpl.addHostSearchHistory(HostSearchHistoryDAOImpl.java:82)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

What am I doing wrong guys. Any help would be nice. Thanks a lot. :-)

You should use the first option suggested by Predrag. Using the second option has two major drawbacks:

1) Low performance. Database will not cache one prepared statement with bind variables, but many of them for all of the combinations of input parameters. That means parsing the statements all over again and purging other prepared statements out of the cache.

2) Security. Statements without bind variables are very vulnerable to SQL injection attacks. It may or may not be the case in you specific example, but generally, suppose that a malicious user (a hacker :)) inputs the following or similar filter criteria for the city or some other field:

' union select null, USERNAME || ',' || PASSWORD, null, null... from USER_PASSWORDS --

He would get all the username/passwords returned as student cities. :) Of course this is just a general example, it may be some other query part or other sensitive data in your database in tables that actually exist.

Short answer - you wrote this

query.setParameter("studentCountry",hostSearchHistory.getCountry());

but in your sb.toString() output you don't have :studentCountry .

Your whole first part of the method should have hardcoded parameter names, like sb.append("s.studentCountry=:studentCountry") , then the second part should work.

Or, use sb.append("s.studentCountry='").append(hostSearchHistory.getCountry()).append("'"); and don't use parameters at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM