Привет всем. У меня не очень много опыта программирования на 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 надо открывать на каждый новый запрос? Если так то что можно сделать? |