Возникли проблемы с чтением строки из таблицы MySQL в Eclipse

#java #jdbc #enums #resultset

#java #jdbc #перечисления #набор результатов

Вопрос:

У меня есть проект купонов, но у меня проблема при попытке прочитать купон в Eclipse. У меня есть таблица категорий, которые связаны с моей таблицей купонов в строке «CATEGORY_ID», которая является int. при использовании метода add я преобразую свое перечисление в int, чтобы без проблем добавить его в CATEGORY_ID.

моя проблема заключается в том, что при попытке ее прочитать я пытаюсь преобразовать ее в СТРОКУ, чтобы получить текстовое значение, однако я получаю исключение.

вот мой код:

КЛАСС ENUM:

 public enum Category {

FOOD(1), ELECTRICITY(2), RESTAURANT(3), VACATION(4), HOTEL(5);

private Category(final int cat) {
    this.cat = cat;
}

private int cat;

public int getIDX() {
    return cat;
}

private Category(String cat1) {
    this.cat1 = cat1;
}

private String cat1;

public String getName() {
    return cat1;
}
}
 

Способ добавления купона в таблицу КУПОНОВ:

 // sql = "INSERT INTO `couponsystem`.`coupons` (`COMPANY_ID`,`CATEGORY_ID`,`TITLE`, `DESCRIPTION`, 
          `START_DATE`, `END_DATE`, `AMOUNT`, `PRICE`, `IMAGE`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";

@Override
    public void addCoupon(Coupon coupon) throws SQLException {
        Connection connection = pool.getConnection();

    try {
        PreparedStatement statement = connection.prepareStatement(ADD_COUPON);
        statement.setInt(1, coupon.getCompanyID());
        statement.setInt(2, coupon.getCategory().getIDX());
        statement.setString(3, coupon.getTitle());
        statement.setString(4, coupon.getDescription());
        statement.setDate(5, (Date) coupon.getStartDate());
        statement.setDate(6, (Date) coupon.getEndDate());
        statement.setInt(7, coupon.getAmount());
        statement.setDouble(8, coupon.getPrice());
        statement.setString(9, coupon.getImage());
        statement.execute();

    } finally {
        pool.restoreConnection(connection);
    }
}
 

Способ получения купона:

 // GET_ONE_COUPON = "SELECT * FROM `couponsystem`.`coupons` WHERE (`id` = ?);";


@Override
    public Coupon getOneCoupon(int couponID) throws SQLException {
    Connection connection = pool.getConnection();

        Coupon result = null;
        
        List<Category> cats = new ArrayList<Category>(EnumSet.allOf(Category.class));
        

        try {

            PreparedStatement statement = connection.prepareStatement(GET_ONE_COUPON);
            statement.setInt(1, couponID);
            ResultSet resultSet = statement.executeQuery();
            resultSet.next();
            result = new Coupon(resultSet.getInt(1), resultSet.getInt(2), Category.valueOf(resultSet.getString(3)),
                    resultSet.getString(4), resultSet.getString(5), resultSet.getDate(6), resultSet.getDate(7),
                    resultSet.getInt(8), resultSet.getDouble(9), resultSet.getString(10));

        } finally {
            pool.restoreConnection(connection);
        }

        return resu<
 

в индексе столбца (3) я пытаюсь преобразовать перечисление в строку, чтобы получить текстовое значение, вот где я получаю исключение.

ИСКЛЮЧЕНИЕ:

 Exception in thread "main" java.lang.IllegalArgumentException: No enum constant coupon.beans.Category.5
    at java.base/java.lang.Enum.valueOf(Enum.java:240)
    at coupon.beans.Category.valueOf(Category.java:1)
    at coupon.dbdao.CouponsDBDAO.getOneCoupon(CouponsDBDAO.java:125)
    at coupon.Program.main(Program.java:65)
 

Надеюсь, я понял свой вопрос. У меня нет проблем с добавлением дополнительной информации.

Ответ №1:

valueOf ожидает строку, соответствующую имени элемента enum, например «FOOD», но похоже, что вы передаете число. Если вы хотите передать идентификатор (номер) из своего перечисления, вам нужен метод для перевода между числом и элементом перечисления. Что-то вроде этого

 //in the enum Category
public static Category categoryFor(int id) {
  switch (id) {
    case 1:
      return FOOD;
      case 2: 
      return ELECTRICITY;
      //... more case
      default:
      return HOTEL;
  }
}
 

а затем назовите это как

 Category.categoryFor(resultSet.getInt(2))
 

или вам нужно сохранить фактическое имя элемента в вашей таблице.

Также вы не должны использовать *, «ВЫБРАТЬ * …», в вашем запросе, но список имен столбцов, чтобы было ясно, какой столбец вы сопоставляете в своем Java-коде: «ВЫБЕРИТЕ COMPANY_ID , CATEGORY_ID , TITLE , …»

Комментарии:

1. должен ли я использовать этот метод в моем классе ENUM? как бы я использовал результирующий набор с определенным методом

2. Да, это для категории enum. Я обновлю ответ

Ответ №2:

Как я правильно понял, вы сохраняете category в coupon качестве константы перечисления в своей модели кода. При сохранении ее в базе данных вы сопоставляете ее целочисленному значению с помощью предоставленных вами методов.

Виновник находится в Category.valueOf(resultSet.getString(3)) методе / части. Enum.valueOf Метод является методом по умолчанию для перечислений, предоставляемых Java и он работает с a String в качестве параметра — вероятно, поэтому вы также используете resultSet.getString(3) вместо resultSet.getInt(3) which было бы более интуитивно понятным.

Из JavaDoc (который вы можете найти здесь) в нем говорится:

… Имя должно точно соответствовать идентификатору, используемому для объявления константы перечисления в этом типе. (Посторонние пробельные символы не допускаются.) …

Это означает, что для того, чтобы valueOf метод заработал, вам нужно вызвать его точно с одним из следующих значений в качестве аргументов: ЕДА, ЭЛЕКТРИЧЕСТВО, РЕСТОРАН, ОТПУСК, ОТЕЛЬ. Вызов его со значениями int, такими как 1, 2, … или 5, приведет к IllegalArgumentException тому, что вы столкнетесь.

Есть два решения для решения проблемы:

  • Либо измените свою модель базы данных, чтобы сохранить значения / константы enum в виде строк в таблице, вызвав toString метод для category значения перед вставкой в базу данных (тогда ваш код, считывающий coupons данные из базы данных, может остаться неизменным).
  • Или вам нужно предоставить собственную пользовательскую реализацию метода « valueOf «, например findCategoryById , который будет работать с целочисленными значениями в качестве аргументов. Написав свой собственный findCategoryById метод, ваш код, вставляющий coupons в базу данных, может остаться неизменным.

Для реализации вашего собственного findCategoryById сигнатура метода в Category перечислении должна выглядеть следующим образом:

 public static Category findCategoryById(int index)
 

Затем вы можете перебрать все доступные константы с помощью Category.values() и сравнить cat с аргументом, переданным методу, и вернуть соответствующее значение на его основе.

В случае, если ни одно из них не совпадает, вы можете просто вернуть null или также выбросить IllegalArgumentException . Последнее я бы лично предпочел, поскольку оно следует подходу «fail fast» и позволяет избежать неприятного и трудоемкого поиска ошибок.


Примечание: Перечисления в Java также имеют автоматически сгенерированный / автоматически назначенный порядковый номер. Вы можете просто запросить ее, вызвав ordinal метод для значения вашего перечисления. В вашем случае ординалы соответствуют самостоятельно присвоенным cat значениям, чтобы вы могли использовать их вместо cat того, чтобы самостоятельно поддерживать атрибуты.

При работе с ординалами стоит упомянуть, что порядок, в котором вы указываете свои константы в перечислении, имеет значение! Когда вы меняете порядок констант, так что ординалы будут. Поэтому вам также нужно быть осторожным при работе с ординалами. Поэтому вы можете предпочесть придерживаться вашего текущего подхода (который совсем не плох и широко используется), поскольку он позволяет избежать проблем с порядком, которые имеют ординалы.

Комментарии:

1. Спасибо за эту подробную информацию, это очень помогло! Теперь у меня есть лучшее понимание.