Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> JTable - проблема с сохранением данных в БД, сохраняется только 1 раз 
V
    Опции темы
ScaD
Дата 5.1.2013, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 5.1.2013

Репутация: нет
Всего: нет



Привет всем. У меня не очень много опыта программирования на java, поэтому прошу у вас помощи.
Моя цель: 
1) Создать форму, на которой находится JTable
2) В эту JTable печатается таблица из БД Apache Derby. Эта JTable редактируема (кроме 0 столбца - там индексы)
4) После редактирования изменения сохраняются в БД по запросу вида: 
Код

UPDATE BadWolf.pharmGroup SET GRNAME = 'Fallout' WHERE IDPHGR=1  //генерится автоматом

Все цели, кроме одной (4), были достигнуты.
В созданной мной программе выполняется только первое изменение таблицы, а последующие не выполняются.
Привожу код:

Код

//simple_class.java
import java.awt.BorderLayout;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class simple_class implements Runnable {
    private static final String driver = "org.apache.derby.jdbc.ClientDriver";
    private static final String url = "jdbc:derby://localhost:1527/BadWolf" ;
    
    //private static final String schema = "BadWolf";
    //private static final String tableName = "pharmGroup" ;
    private static final String qryPrintPhGr = "SELECT idPhGr, grName, description FROM BadWolf.pharmGroup";
    
    private static Connection conn = null;
    private static Statement stat = null;
    private static ResultSet rs = null;
    
    public static void main(String[] args) throws Throwable   {
        //SwingUtilities.invokeLater(new simple_class());
        new simple_class().run();
    }

    @Override
    public void run() {
        
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url);
            stat = conn.createStatement();
            rs = stat.executeQuery(qryPrintPhGr);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        
        //(+) setTableName() - надо задать для создания запроса
       
        TableModelDerby model = null;
        try {
          model = new TableModelDerby(rs);
          model.setTableName("BadWolf.pharmGroup");//schema + "." + tableName);
        } catch (ClassNotFoundException e) {e.printStackTrace();
        } catch ( SQLException e) {e.printStackTrace();
        }
        
        JTable table = new JTable(model);
        
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(new JScrollPane(table), BorderLayout.CENTER);
        
        JFrame frame = new JFrame("Derby Database Table Model");
        frame.setLocationRelativeTo(null);
        frame.setSize(640, 480);
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}



Код

//TableModelDerby.java
import javax.swing.table.AbstractTableModel;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;

import java.util.ArrayList;

public class TableModelDerby extends AbstractTableModel {
    private ArrayList<String> columnNames = new ArrayList<String>();
    private ArrayList<Class> columnTypes = new ArrayList<Class>();
    private ArrayList<Integer> typesInt = new ArrayList<Integer>();
    private ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>();
    
    private String tableName = "";
    private ResultSet rs = null;
    
    private String id = "";
    
    ;
    /**
     * Конструктор по умосчанию
     */
    public TableModelDerby() {}
    
    /**
     * Не забыть указать setTableName(String tableName).
     * Иначе не будет работать сохранение в БД, ибо sql запрос неверен!
     * @param ResultSet rs
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public TableModelDerby(ResultSet rs) throws ClassNotFoundException, SQLException {
        this.setDataSource(rs);
    }
    
    /**    
     * Не забыть указать setTableName(String tableName).
     * Иначе не будет работать сохранение в БД, ибо sql запрос неверен!
     * @param rs
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public void setDataSource(ResultSet rs) throws ClassNotFoundException, SQLException {
        ResultSetMetaData rsmd = rs.getMetaData();
        columnNames.clear();
        columnTypes.clear();
        data.clear();

        int columnCount = rsmd.getColumnCount();
        for (int i = 0; i < columnCount; i++) {
            columnNames.add(rsmd.getColumnName(i + 1));
            Class type = Class.forName(rsmd.getColumnClassName(i + 1));
            columnTypes.add(type);
            typesInt.add(rsmd.getColumnType(i+1));
        }
        fireTableStructureChanged();
        while (rs.next()) {
            ArrayList rowData = new ArrayList();
            for (int i = 0; i < columnCount; i++) {
                if (columnTypes.get(i) == String.class)
                    rowData.add(rs.getString(i + 1));
                else
                    rowData.add(rs.getObject(i + 1));
            }
            data.add(rowData);
            this.fireTableRowsInserted(data.size() - 1, data.size() - 1);
        }
        this.rs = rs;
    }
    
    /**
     * Указывается в формате: Schema.TableName
     * @param String tableName
     */
    public void setTableName(String tableName){
        this.tableName = tableName;
    }
    
    public int getColType(int col) {
        return typesInt.get(col);
    }
    
    @Override
    public int getRowCount() {
        synchronized (data) {
            return data.size();
        }
    }
    
    @Override
    public int getColumnCount() {
        return columnNames.size();
    }
    
    @Override
    public Object getValueAt(int row, int col) {
        synchronized (data) {
            return data.get(row).get(col);
        }
    }
    
    @Override
    public String getColumnName(int col) {
        return columnNames.get(col);
    }
    
    @Override
    public Class getColumnClass(int col) {
        return columnTypes.get(col);
    }
    
    @Override
    public boolean isCellEditable(int row, int col) {
        if(col==0)
            return false;
        return true;
                
    }
 
    @Override
    public void setValueAt(Object val, int row, int col) {
        if (tableName == ""){
            System.out.println("Неверное имя таблицы или схемы!");
            return;
        }
        //for example: UPDATE employee SET Salary = 1400.0 WHERE 
        String query = "UPDATE " + tableName + " SET " + getColumnName(col)
                + " = " + getValForSQL(val, col) + " WHERE " + getColumnName(0) + "=" + getValForSQL(getValueAt(row, 0),0);
            //created the SQL query
        //TODO надо что то делать с праймори кеем. сейчас стоит навигация по первому полю.
        //TODO передавать сюда праймори кей(предусмотреть составной)
        //TODO или както извлекать его из самой БД
        //////////////////////////////////////////////////////////////////////
        System.out.println(query);    //print the SQL query //TODO create SQL query END(parameters)
        int err = -1;
        try {
            rs.getStatement().executeUpdate(query);    //execute query as DML
        } catch (SQLException e) {
            e.printStackTrace();
            err = err + 10;
        }
        //System.out.println(data.get(row).get(col));
        data.get(row).set(col, val);
        fireTableCellUpdated(row, col);
        //System.out.println(data.get(row).get(col));
        if(err<0)
            System.out.println("Query is completed successfully");
        else
            System.out.println("Query is pending");
    }
    
    /**
     * Возвращает значение для изменяемого поля. Зависит от типа в БД.
     * для CHAR, VARCHAR, DATE -> 'value'
     * для остальных без кавычек
     */
    public String getValForSQL(Object val, int col){
        if (val == null) {
            return "null";}
        int currentType = getColType(col);
        if(currentType == Types.CHAR || currentType == Types.VARCHAR || currentType == Types.DATE)
            return "\'" + val.toString() + "\'";
        return val.toString();
    }
}

Пишет ошибку:
Набор результатов (ResultSet) не открыт.  Убедитесь, что опция автоматического принятия выключена (OFF).
Я так понимаю что все переменные в TableModel зануляются, но что с этим сделать(ResultSet не открыт).
Может быть этот код вобще неправитьно написан(в TableModel нельзя объявлять никаких переменных, которые содержат данные таблицы).
Или ResultSet надо открывать на каждый новый запрос? Если так то что можно сделать?

Это сообщение отредактировал(а) ScaD - 5.1.2013, 23:23

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  code.zip 7,02 Kb
PM MAIL   Вверх
dorogoyIV
Дата 6.1.2013, 02:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1503
Регистрация: 26.3.2007

Репутация: 3
Всего: 46



строка 130
запрос должен быть такого вида:
Код

UPDATE [table name] SET " " = ' ' WHERE " " = ' '

т.е. имя столбца в двойных кавычках
PM MAIL   Вверх
ScaD
Дата 6.1.2013, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 5.1.2013

Репутация: нет
Всего: нет



Дело не в запросе. Во первых: он выполняется первый раз (и через ij тоже нормально выполняется).
Сформированный запрос перед исполнением выводится в консоль.
Вывод:
Код

UPDATE BadWolf.pharmGroup SET GRNAME = 'Fallout 2                                                        ' WHERE IDPHGR = 1

Во вторых: Имя столбца в двойных кавычках можно не писать.
Я это читал тут:Apache Derby.
Цитата

 Чтобы лучше представлять себе назначение таблицы или отдельного столбца, следует выбирать для них соответствующие имена. Соглашение об используемых именах может отличаться в различных базах данных. В системе баз данных Apache Derby отдельные имена:

    Не чувствительны к регистру;
    Имеют длину не более 128 символов;
    Должны начинаться с буквы;
    Должны содержать только буквы в кодировке Unicode, символы подчеркивания и цифры в кодировке Unicode.

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

dorogoyIV, даже если сделать как Вы сказали, то ничего не изменяется в работе программы.
При запуске программы, происходит открытие окна, отрисовка таблицы. После изменения в таблице выполняется запрос, а уже потом если изменять, допустим еще одно значение, то выдает ошибку.

Тогда еще вопрос: значение должно быть всегда в кавычках (') или только строковые и дата?

Это сообщение отредактировал(а) ScaD - 6.1.2013, 12:52
PM MAIL   Вверх
dorogoyIV
Дата 6.1.2013, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1503
Регистрация: 26.3.2007

Репутация: 3
Всего: 46



Цитата(ScaD @  6.1.2013,  12:42 Найти цитируемый пост)
или только строковые и дата

да, только эти, еще какие то - не помню щас

так ошибка в строке 140 ?
наверное надо по новой получить ResultSet
PM MAIL   Вверх
ScaD
Дата 6.1.2013, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 5.1.2013

Репутация: нет
Всего: нет



так там надо получать каждый раз ResultSet?
-------------------------
а.... хотя.... тамже
Код

rs.getStatement().executeUpdate(query);

там вобще каким боком ResultSet?
Можно же поставить в TableModel еще одну переменную
Код

private Statement state = null;

и потом получать ResultSet когда надо.
(но надо учесть, что в setDataSource(ResultSet rs) при инициализации основных переменных [ArrayList data, и прочие] нужно инфу вытаскивать из ResultSeta [там же результат выполненого запроса])
-------------------------
А вообще, если по уму, то как правильно сделать такое?
ну в смысле: как правильно сохранить внесенные изменения в таблицу
(может лучше по кнопке сделать? т.е. сначала редактируем таблицу, а потом делаем большой SQL запрос на обновление. или он будет слишком много перезаписывать(если изменений мало)?)
-------------------------
все получилось. сделал так:
Код

    public void setDataSource(ResultSet rs) throws ClassNotFoundException, SQLException {
        this.setStatement(rs.getStatement());   //добавил это
        //...

и изменил сдесь:
Код

public void setValueAt(Object val, int row, int col) {
//...
        try {
            //rs.getStatement().executeUpdate(query);    //было
            getStatement().executeUpdate(query);    //убрал rs - ибо нафиг не нужен
        } catch (SQLException e) {    //...

ах да еще добавил getStatement() и setStatement():
Код

    private void setStatement(Statement statement) {
        this.state = statement;
    }
    private Statement getStatement() {
        return this.state;
    }

вроде все.

если кому понадобится, приложу рабочие файлы java

Это сообщение отредактировал(а) ScaD - 6.1.2013, 14:52

Присоединённый файл ( Кол-во скачиваний: 11 )
Присоединённый файл  code_ok.zip 7,55 Kb
PM MAIL   Вверх
ScaD
Дата 6.1.2013, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 5.1.2013

Репутация: нет
Всего: нет



Еще вопрос:
Надо что то делать с праймори кеем. Сейчас стоит навигация по первому полю(что не есть гуд).
Как его можно извлечь его из самой таблицы? (а если он составной?)

Это сообщение отредактировал(а) ScaD - 6.1.2013, 14:41
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1017 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.