2012-06-13 4 views
1

Цель состоит в том, чтобы написать метод удобства, который возвращает ResultSet из запроса JDBC с помощью простой формы вызова на стороне клиента.Как подготовить аргумент типа: List <Entry <? extends Класс <?>,? >>

я написал что-то вроде этого:

public class JdbcQueryManager { 
    public static ResultSet executePreparedStatementWithParameters(
     Connection jdbcConnection, String sqlQuery, 
     Map.Entry<? extends Class<?>, ?>... sqlQueryParameters) 
     throws JdbcQueryFailureException { 
    return executePreparedStatementWithParameters(jdbcConnection, sqlQuery, 
     Arrays.asList(sqlQueryParameters), ResultSet.TYPE_FORWARD_ONLY, 
     ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); 
    } 
    private static ResultSet executePreparedStatementWithParameters(
     Connection jdbcConnection, String sqlQuery, 
     List<Map.Entry<? extends Class<?>, ?>> sqlQueryParameters, 
     int resultSetType, int resultSetConcurrency, int resultSetHoldability) 
     throws JdbcQueryFailureException { 
    try { 
     PreparedStatement preparedStatement = 
      jdbcConnection.prepareStatement(sqlQuery, resultSetType, 
       resultSetConcurrency, resultSetHoldability); 
     for (int i = 0; i < sqlQueryParameters.size(); i++) { 
     int sqlQueryParameterIndex = i + 1; // SQL parameters are 1-based 
     Entry<? extends Class<?>, ?> sqlQueryParameter = 
      sqlQueryParameters.get(i); 
     Class<?> sqlQueryParameterClass = sqlQueryParameter.getKey(); 
     if (sqlQueryParameterClass == Integer.class) { 
      int sqlQueryParameterIntegerValue = 
       (Integer) sqlQueryParameter.getValue(); 
      preparedStatement.setInt(sqlQueryParameterIndex, 
       sqlQueryParameterIntegerValue); 
     } else if (sqlQueryParameterClass == String.class) { 
      String sqlQueryParameterStringValue = 
       (String) sqlQueryParameter.getValue(); 
      preparedStatement.setString(sqlQueryParameterIndex, 
       sqlQueryParameterStringValue); 
      // TODO: accept other types, not just String and Integer 
     } else { 
      throw new JdbcQueryFailureException(new IllegalArgumentException(
       sqlQueryParameterClass.getName())); 
     } 
     } 
     ResultSet resultSet = preparedStatement.executeQuery(); 
     return resultSet; 
    } catch (SQLException sqlException) { 
     throw new JdbcQueryFailureException(sqlException); 
    } 
    } 
} 

с помощью этого класса удобства:

public class QueryParameter<T> extends AbstractMap.SimpleEntry<Class<T>, T> { 
    @SuppressWarnings("unchecked") 
    public QueryParameter(T parameterValue) { 
    super((Class<T>) parameterValue.getClass(), parameterValue); 
    } 
} 

, чтобы иметь возможность выполнить инструкцию JDBC SQL, как это:

ResultSet resultSet = 
    JdbcQueryManager.executePreparedStatementWithParameters(jdbcConnection, 
     sqlQuery, new QueryParameter<String>("AnswerRequest"), 
     new QueryParameter<Integer>(42)); 

. .. как я могу сделать это лучше?

В частности, мои недоумения лежат в использовании этого, казалось бы, сложной, возможно, ненужной форма:

List<Map.Entry<? extends Class<?>, ?>> 
+0

Боковое примечание: ваш форматтер должен принимать не менее 150 символов в строке. Это, как правило, причина, почему ИМО. – sp00m

+1

Причина, почему ... что? :) Вы имеете в виду «формат кода с большим количеством символов в строке»/«более широкий», в основном? – Robottinosino

+0

ИМХО, вы просто усложняете свою жизнь целым материалом QueryParameter. Почему бы вам не использовать нечто вроде 'execute (sqlQuery," AnswerRequest ", 42)' вместо этого? Я как-то написал что-то вроде этого, и он работает (с 4 различными БД). – maaartinus

ответ

3

Там нет значения при переходе в списке Map.Entry<? extends Class<?>, ?> - вы пытаетесь сказать вашему методу, какой класс каждому параметр. Не делайте этого !!!

Вопреки распространенному мнению, вы не должны использовать различные типизированных preparedStatement.setXXX() методы, если вы используете «базовые» Java объекты (обернутые примитивы и Dates), просто используйте preparedStatement.setObject(index, object) и JDBC драйвер будет выяснить, что делать!

Единственный раз, когда вам нужно использовать типизированный сеттер, является ли ваш объект не одним из «основных» типов. Если вам это действительно нужно, просто используйте instanceof для проверки каждого параметра, затем вы напишете какой-нибудь код, чтобы, возможно, извлечь значение String, но вы все равно можете позвонить preparedStatement.setObject(index, object) с этой строкой.


я написал что-то вроде этого я и я просто использовал:

public static ResultSet executePreparedStatementWithParameters(
    Connection jdbcConnection, String sqlQuery, Object... parameters) 

и она работает просто отлично.

+0

Я посмотрел на источник несколько драйверов JDBC, реализующих setObject (например, Sqlite от Xerial, pgjdbc для PostreSQL и т. д.), и большинство из них просто выполняют серию проверок экземпляров (Timestamp, Double, Integer, Float. java.util.Date и т. д.) перед установкой их типа Вы делаете большой упор в своем «не делай этого !!!», как будто в нем есть какой-то вред, он просто лишний и, таким образом, вводит ненужный потенциальный источник ошибок, нарушая СУХИЕ из-за дублирования. что-то похожее на себя, не могли бы вы поделиться кодом? – Robottinosino

+0

Как я мог не принять этот хороший ответ, хотя. :-) – Robottinosino

Смежные вопросы