Ich fand eine Lösung nach Berücksichtigung, was @mustaccio in seinem Kommentar zu meiner ursprünglichen Frage sagte. Ich nahm auch einen Teil der Lösung von this stackoverflow question und benutzte es in meiner eigenen Lösung.
Das Hauptproblem ich dynamisch eine Object[]
Array zur Laufzeit zu schaffen wurde mit, da man nicht dynamisch Elemente zu einem Object[]
Array hinzufügen kann. Sie müssen eine definierte Größe haben, wenn sie initialisiert werden.
Zuerst erstelle ich eine Arraylist der Zeichenketten queryArgs
. Jedes Mal, wenn eine der if-Bedingungen wahr ist und wir der Abfrage eine AND
-Anweisung hinzufügen, füge ich auch eine weitere Codezeile hinzu, die den Wert hinzufügt, der in preparedStatement in die queryArgs
-Arraylist eingefügt werden soll. Sobald das erledigt ist, erstelle ich ein neues Object[]
Array, dessen Größe auf die Größe der queryArgs
Arraylist initialisiert wird. Schließlich durchlaufe ich jedes Element im Array Object[]
und setze sie gleich den Werten in 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... */
});
}
Der Ausreißer ist, dass eines der dynamischen AND
Aussagen oben wie folgt geschrieben wird:
AND column4 IN ('x','y','z','etc..')
, wobei die Werte innerhalb der Klammern zur Laufzeit auch dynamisch sind. Mein Service erhält einen String-Wert, der wie folgt aussieht:
String queryParams.value4 = "x,y,z,etc...";
ich die preparedStatement wie dies nicht schreiben kann: AND column4 IN (?)
und dann stecken Sie einfach in queryParams.value4
weil es queryParams.value4
als Stringliteral behandeln, was zu Fehlern führt.
Um dieses Problem zu lösen, erstelle ich eine andere Arraylist der Zeichenfolgen value4Array
. Ich durchlaufe jedes Zeichen in queryParams.value4
, und ich überprüfe, ob das aktuelle Zeichen in der Schleife einem Komma entspricht, unserem Begrenzer. Wenn dies der Fall ist, erzeuge ich eine Teilzeichenkette aller Zeichen, die zu diesem Komma führen, und füge diese neu erzeugte Zeichenkette zu value4Array
hinzu. Der nächste Schritt besteht darin, die dynamische AND column4 IN (?)
-Anweisung zu erstellen.Ich mache das, indem ich jeden String-Wert in der value4Array
Arraylist, die wir gerade erstellt haben, durchläuft und eine sql.append("?")
macht, basierend darauf, wie viele Strings in value4Array
sind. Danach ist der Rest der Logik derselbe wie meine obige Lösung.
/* 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));
}
}
Sicher können Sie das 'Objekt []' zur Laufzeit mit der entsprechenden Größe erstellen. Was hast du bisher versucht? – mustaccio
@mustaccio Danke für diesen Hinweis! Das hat wirklich geholfen. Da Sie zur Laufzeit die Größe von Arrays in Java nicht ändern können, war es mir möglich, eine ziemlich einfache Lösung zu finden, um das 'Objekt []' zur Laufzeit dynamisch mit der passenden Größe zu initialisieren. Ich habe noch ein anderes Problem, das ich beheben muss, bevor ich meine Lösung poste – bscott
Das Problem ist, dass eine der dynamischen AND-Anweisungen wie folgt geschrieben wird: 'AND column1 IN ('x', 'y', 'z', 'etc ..') ', wobei die Werte innerhalb der Klammern zur Laufzeit ebenfalls dynamisch sind. Ich kann nicht die preparedStatement wie 'AND column1 IN (?)' Schreiben und dann den kommagetrennten String-Wert (dh 'String Werte =" x, y, z, etc ... ";") in, weil es behandelt den kommagetrennten Zeichenfolgenwert als Zeichenfolgenliteral, was zu Fehlern führt. Ich bin dabei, dieses Problem zu beheben, und ich werde zurückkommen, wenn ich es behoben habe. – bscott