Я нашел решение после учета того, что @mustaccio сказал в своем комментарии к моему первоначальному вопросу. Я также принял участие в решении от this stackoverflow question и использовал его в своем собственном решении.
Основная проблема, с которой я столкнулся, заключалась в динамическом создании массива Object[]
во время выполнения, поскольку вы не можете динамически добавлять элементы в массив Object[]
. При инициализации они должны иметь определенный размер.
Во-первых, я создаю arraylist строк под названием queryArgs
. Каждый раз, когда одно из условий if доказывается верно, и мы добавляем в запрос оператор AND
, я также добавляю еще одну строку кода, которая добавляет значение, которое должно быть вставлено в подготовленноеStatement в arraylist queryArgs
. Как только это будет сделано, я создаю новый массив Object[]
, размер которого инициализируется размером queryArgs
arraylist. Наконец, я прокручиваю каждый элемент в массиве Object[]
, устанавливая их равными значениям в queryArgs
.
private JdbcTemplate jdbcTemplate;
List<QueryResults> jdbcQuery(QueryParams queryParams) {
/* base query */
StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 ");
/* stores the dynamic preparedStatement arguments */
List<String> queryArgs = new ArrayList<>();
if(someCondition){
sqlQuery.append("And column1 = ? ");
queryArgs.add(queryParams.value1);
}
if(someCondition2){
sqlQuery.append("And column2 = ? ");
queryArgs.add(queryParams.value2);
}
if(someCondition3){
sqlQuery.append("And column3 = ? ");
queryArgs.add(queryParams.value3);
}
//etc...
/* this is the part I used from the above stackoverflow question */
Object[] preparedStatementArgs = new Object[queryArgs.size()];
for(int i = 0; i < preparedStatementArgs.length; i++){
preparedStatementArgs[i] = queryArgs.get(i);
}
/* Lastly, execute the query */
return this.jdbcTemplate.query(sqlQuery.toString(),
preparedStatementArgs, (rs, rowNum) -> {
QueryResults result = new QueryResults();
/* store the results of the query... */
});
}
останца является то, что один из динамических AND
утверждений выше написано как это:
AND column4 IN ('x','y','z','etc..')
, где значение внутри скобок также является динамическим во время выполнения. Моя служба получает строковое значение, которое выглядит следующим образом:
String queryParams.value4 = "x,y,z,etc...";
Я не могу написать PreparedStatement так: AND column4 IN (?)
, а затем просто подключить в queryParams.value4
, потому что он будет относиться к queryParams.value4
как строковый литерал, что приводит к ошибкам.
Чтобы решить эту проблему, я создаю еще один arraylist строк, называемый value4Array
. Я прокручиваю каждый символ в queryParams.value4
, и я проверяю, равен ли текущий символ в цикле запятой, нашим разделителем. Если это так, я создаю подстроку всех символов, предшествующих этой запятой, и добавьте эту вновь созданную строку в value4Array
.
Следующий шаг - создать динамический оператор AND column4 IN (?)
.Я делаю это, перебирая каждое строковое значение в массиве value4Array
, который мы только что создали, и делаем sql.append("?")
, исходя из того, сколько строк находится в value4Array
. После этого остальная часть логики совпадает с моим решением выше.
/* this function takes the comma delimited string literal (value4 : "x,y,z,etc...")
and parses it into an array of strings. */
private List<String> parseValue4(String value4){
int valueIndex= 0;
List<String> value4Array = new ArrayList<>();
for(int i = 0; i < value4.length(); i++){
if(value4.charAt(i) == ','){
value4Array.add(value4.substring(valueIndex, i));
valueIndex = i + 1;
}
else if(i == value4.length() - 1){
value4Array.add(value4.substring(valueIndex, value4.length()));
}
}
return value4Array;
}
if(someCondition4){
List<String> value4Array = parseValue4(queryParams.value4);
sqlQuery.append("And column4 IN ("); /* base AND statement */
for(int i = 0; i < value4Array.size(); i++){
if(i == value4Array.size() - 1)
sqlQuery.append("?)");
else /* dynamically appending ?'s */
sqlQuery.append("?,");
queryArgs.add(value4Array.get(i));
}
}
Наверняка вы можете создать 'Object []' во время выполнения с соответствующим размером. что ты уже испробовал? – mustaccio
@mustaccio Спасибо за этот совет! Это действительно помогло. Поскольку вы не можете изменять размеры массивов в Java во время выполнения, я смог придумать довольно простое решение для динамической инициализации 'Object []' с соответствующим размером во время выполнения. У меня все еще есть другая проблема, которую мне нужно исправить, прежде чем я опубликую свое решение, хотя – bscott
Проблема в том, что один из динамических операторов 'AND' написан так:' AND column1 IN ('x', 'y', 'z', 'и т. д.') ', где значения внутри круглых скобок также будут динамическими во время выполнения. Я не могу написать подготовленноеStatement как 'AND column1 IN (?)', А затем подключить строковое значение, разделенное запятыми (то есть 'String values =" x, y, z, etc ... ";'), потому что это будет обрабатывать строковое значение, разделенное запятыми, как строковый литерал, что приводит к ошибкам. Я в процессе исправления этой проблемы, и я вернусь, когда я ее исправил. – bscott