0

I'm trying to write a search, using Hibernate that would run search on different types of variables. I have a model Movie, that has properties: title, director, genre, year. Title, director, genre are strings, year is an int.

In the jsp file I have a select that will choose the property by which I want to search, and then a text input where I enter the property value. So it can be for example: Title: Some title, Year: 2000, etc.

I pass those values to the controller. Now, I have such methods in my hibernate classes:

public Movie findByProperty(String searchCriteria, String criteriaValue) {
    Criteria criteria = getCurrentSession().createCriteria(Movie.class);
    Movie movie = (Movie) criteria.add(Restrictions.eq(searchCriteria, criteriaValue)).uniqueResult();
    return movie; 
}

and

public Movie findByProperty(String searchCriteria, String criteriaValue) {
    jdbcMovieDao.openCurrentSession();
    Movie entity = jdbcMovieDao.findByProperty(searchCriteria, criteriaValue);
    jdbcMovieDao.closeCurrentSession();
    return entity;
}

And in the controller:

public String findMovieBy(ModelMap modelMap, @RequestParam(required = true) String searchCriteria,
        @RequestParam(required = true) String criteriaValue) {
    Movie movie = movieService.findByProperty(searchCriteria, criteriaValue);

It works fine when I select String properties, but I also want to be able to select year as criterium. I could probably put some if here, but I don't want to do it - not unless there is a nicer way. Can anyone tell me how to do it 'properly'. Please, be gentle, I'm a beginner. :-)

czmadzia
  • 1
  • 1

2 Answers2

0

I guess the problem is that year is a Number not String?

I think you could propably get it to work with Restriction.sqlRestriction and CAST so the "database"-side returns a String too... with something like that ... (assuming Oracle as DB)

Restrictions.sqlRestriction("CAST({alias}.propertyName as VARCHAR2(255)) = ?", criteraValue, Hibernate.STRING)

However you're going to do a lot of unessesary casting there so I'd stick with the ifs ;)

Also, I'm not sure if CAST would cast varchar2 to varchar2 or if that would give an error.

Better solution would be using the Hibernate Metamodel (http://hibernate.org/orm/tooling/) to determine the property type but that's not gonna work without some if's I'm afraid

tom
  • 1,455
  • 1
  • 8
  • 13
0

Restrictions.eq takes Object as the second argument. Just replace "String criteriaValue" by "Object criteriaValue" in findByProperty method, and you should be able to use both String and (autoboxed) int value in the search. Of course the controller will have to pass int value for a year, not a String.

Your current implementation has other issue, it couples URL parameter searchCriteria with names of Movie class fields, used in the first argument of Restrictions.eq. The tight coupling between the URL and a model is not a good idea in general.

A malicious user could also use your URL in ways you don't expect, for example it's very easy to steal your whole movie database by subsequent queries with searchCriteria=id and subsequent natural numbers as searchValue.

You could make different controller methods for each type of search, which would make Spring convert the year to int automatically while calling the appropriate controller method. This would decouple your web interface and model too, for example you could change the URL syntax without major refactoring of the application.

Alternatively, you can make one controller method with four parameters and refactor the DAO to allow for search by more than one query key.

Whatever you're going to do, don't couple the URL with model field names, and don't use an URL parameter being either String or int depending on the context. It will never make a clean design internally, and it may hamper any future RESTful description of your web interface (for example using WADL), because you won't be able to specify a type of criteriaValue in URL in a consistent way.

Olaf
  • 1
  • 1