HQL: variable column

2019-07-23 13:38发布

问题:

I'm able to set variable values for "where" restrictives:

Query criteria = session.createQuery(
  "select test.col1, test.col2, test.col3
  "from Test test " +
  "where test.col = :variableValue ");
criteria.setInteger("variableValue", 10);

But is it possible to set variable column like this?

String variableColumn = "test.col1";
Query criteria = session.createQuery(
  "select test.col1, test.col2, test.col3
  "from Test test " +
  "where :variableColumn = :variableValue ");
criteria.setInteger("variableValue", 10);
criteria.setString("variableColumn", variableColumn);

This is the result:

Exception in thread "main" Hibernate: select .... where ?=? ...
org.hibernate.exception.SQLGrammarException: could not execute query
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
    ...
    at _test.TestCriteria.main(TestCriteria.java:44)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Conversion failed when converting the nvarchar value 'test.col1' to data type int.
    ...

UPDATE (working solution):

Query criteria = session.createQuery(
  "select test.col1, test.col2, test.col3
  "from Test test " +
  "where (:value1 is null OR test.col1 = :value1) AND 
         (:value2 is null OR test.col2 = :value2) "

回答1:

Does this make sense in your application:

String query =  "select test.col1, test.col2, test.col3" + 
  "from Test test " +
  "where {columnName} = :variableValue ";
Object variableValue = // retrieve from somewhere
String columnName = // another retrieve from somewhere
query = query.replace("{columnName}", columName);
// Now continue as always

This is generally a naive query constructor. You may need to refactor this idea to a separate utility/entity-based class to refine (e.g. SQL injection) the queries before execution.



回答2:

You can set the column name as part of the string. For security you may do the SQL escaping manually, but at the end you can achieve this.

To avoid SQL injection you can use commons class:

String escapedVariableColumn = org.apache.commons.lang.StringEscapeUtils.escapeSql(variableColumn);

Query criteria = session.createQuery(
  "select test.col1, test.col2, test.col3
  "from Test test " +
  "where " + escapedVariableColumn + " = :variableValue ");
criteria.setInteger("variableValue", 10);