Hay de hecho hay manera fácil de hacer esto en JDBC. Algunos Los controladores JDBC parecen admitir PreparedStatement#setArray()
en la cláusula IN
. No estoy seguro de cuáles son.
Se podía usar un método de ayuda con String#join()
y Collections#nCopies()
para generar los marcadores de posición para IN
cláusula y otro método de ayuda para configurar todos los valores en un bucle con PreparedStatement#setObject()
.
public static String preparePlaceHolders(int length) {
return String.join(",", Collections.nCopies(length, "?"));
}
public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
for (int i = 0; i < values.length; i++) {
preparedStatement.setObject(i + 1, values[i]);
}
}
He aquí cómo se podría utilizar:
private static final String SQL_FIND = "SELECT id, name, value FROM entity WHERE id IN (%s)";
public List<Entity> find(Set<Long> ids) throws SQLException {
List<Entity> entities = new ArrayList<Entity>();
String sql = String.format(SQL_FIND, preparePlaceHolders(ids.size()));
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
) {
setValues(statement, ids.toArray());
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
entities.add(map(resultSet));
}
}
}
return entities;
}
private static Entity map(ResultSet resultSet) throws SQLException {
Enitity entity = new Entity();
entity.setId(resultSet.getLong("id"));
entity.setName(resultSet.getString("name"));
entity.setValue(resultSet.getInt("value"));
return entity;
}
Tenga en cuenta que algunas bases de datos tienen un límite de la cantidad permitida de los valores en la cláusula IN
. Oracle, por ejemplo, tiene este límite en 1000 artículos.
Eso es lo que estamos haciendo en este momento, pero lo que esperaba era que hubiera una forma uniforme de hacerlo sin SQL personalizado ... – Uri
Además, si es algo así como Oracle, tendrá que volver a analizar la mayoría de las declaraciones. – orbfish