Foro sobre Java SE > Problema Java o SQL?
Habría que ver cómo haces esa consulta SQL, y cómo están definidas esas tablas.
Como haga para pasartelas , asi podes verlas
Este es el codigo de insercion:
public String InsertarPrestacion(Prestacion Pres)
{
String resultado="";
try{
AbrirConexion();
st=con.createStatement();
String sql="insert into Prestacion (Codigo, Nombre, Descripcion, CostoPrestacion, TipoPractica)values"
+ " ("+Pres.getCodigo()+",'"+Pres.getNombre()+"','"+Pres.getDescripcion()+"',"+Pres.getCostoPrestacion()+","+Pres.getTipoPractica()+")";
st.executeUpdate(sql);
resultado="Prestacion insertada con exito";
}
catch(SQLException e){
System.out.println("No se pudo realizar la insercion:"+ e.getMessage());}
return resultado;
}
Este es el metodo que hice para cargar el combobox, ya que el tipo de practica debe seleccionarse desde el mismo: (Aclaracion: los datos de la tabla tipo de practica, se los carge manualmente):
public ArrayList getFormaPago()
{
ArrayList lista= new ArrayList();
String nombre;
String descripcion;
FormaPago FP=null;
try
{
AbrirConexion();
st=con.createStatement();
String sql="select Nombre, Descripcion from FormaPago";
rs=st.executeQuery(sql);
while(rs.next())
{
nombre=rs.getString("Codigo");
descripcion=rs.getString("Descripcion");
FP=new FormaPago();
FP.setNombre(nombre);
FP.setDescripcion(descripcion);
lista.add(FP);
}
}
catch(SQLException e)
{System.out.println("Error en la consulta:"+ e.getMessage());}
return lista;
}
Las tablas "tratamiento", tiene una foreign key que es tipopractica
la tabla "tipopractica", tiene su primary key que es codigo
He relacionado tratamiento con tipopractica mediante estas claves.
Aqui llamo al metodo para cargar el combo, desde el JFrame de Tratamiento
public void CargarComboTipoPractica()
{
ArrayList r=Conexion.getInstance().getTipoPractica();
if(r!=null)
{ try {
DefaultComboBoxModel modelo=new DefaultComboBoxModel();
Iterator iter=r.iterator();
while(iter.hasNext())
{ modelo.addElement(iter.next());}
this.ComboTipoPractica.setModel(modelo);
}
catch(Exception ex)
{ JOptionPane.showMessageDialog(this,"No se pudo realizar la carga:" + ex.getMessage());}
}
else
{ JOptionPane.showMessageDialog(this,"No tiene nada registrado");}
}
Y por ultimo, esto es lo que hice para mostrar el tratamiento cargado,
public void CargarTabla()
{
DefaultTableModel modelo= new DefaultTableModel();
this.TablaPrestaciones.setModel(modelo);
//Establesco titulos para cada columna
String titColumna[];
titColumna=new String[5];
titColumna[0]="Codigo Prestación";
titColumna[1]="Nombre";
titColumna[2]="Descripción";
titColumna[3]="Costo Prestación";
titColumna[4]="Tipo Practica";
//Declaro una variable del tipo ArrayList para asignarle el metodo
ArrayList lis= Conexion.getInstance().getPrestacion();
Object[][]data=new String [lis.size()][5];
try
{
Iterator ite=lis.iterator();
Prestacion Pres=null;
int ind=0;
while(ite.hasNext())
{
Pres=(Prestacion)ite.next();
data[ind][0]=String.valueOf(Pres.getCodigo());
data[ind][1]=Pres.getNombre();
data[ind][2]=Pres.getDescripcion();
data[ind][3]=String.valueOf(Pres.getCostoPrestacion());
data[ind][4]=String.valueOf(Pres.getTipoPractica());
ind++;
}
modelo=new DefaultTableModel(data,titColumna);
this.TablaPrestaciones.setModel(modelo);
}
catch(Exception e){System.out.println("Error al cargar tabla"+e.getMessage());}
}
Me faltaba este codigo, es lo que puse en el boton insertar, en el JFrame :
int cod=Integer.parseInt(txtFormateCodigo.getText());
String nom=txtNombrePrestacion.getText();
String des= txtDescripcion.getText();
Double cos=Double.parseDouble(txtFormateCosto.getText());
int tp=ComboTipoPractica.getSelectedIndex();
//Crea el nuevo tratamiento o prestacion, es lo mismo
Prestacion p=new Prestacion(cod,nom,des,cos,tp);
Conexion.getInstance().InsertarPrestacion(p);
JOptionPane.showMessageDialog(this, "Prestación Registrada");
He visto un par de cosas que no me convencen.
En getFormaPago()
String sql="select Nombre, Descripcion from FormaPago";
y más abajo...
nombre=rs.getString("Codigo");
descripcion=rs.getString("Descripcion");
Haces un SELECT sobre Nombre, pero le asignas el contenido de la columna Codigo.
En CargarComboTipoPractica
while(iter.hasNext())
{ modelo.addElement(iter.next());}
this.ComboTipoPractica.setModel(modelo);
}
El método addElement ya notifica al Combo que se ha añadido un nuevo elemento.
Puedes hacerlo así:
DefaultComboBoxModel modelo=new DefaultComboBoxModel();
this.ComboTipoPractica.setModel(modelo);
Iterator iter=r.iterator();
while(iter.hasNext())
{ modelo.addElement(iter.next());}
He reescrito el siguiente método, usando genéricos y con un ForEach. Creo que así se entiende mejor. El método getPrestación debería devolver una List<Prestacion>
public void cargarTabla() {
//Establesco titulos para cada columna
String[] titColumna = new String[5];
titColumna[0] = "Codigo Prestación";
titColumna[1] = "Nombre";
titColumna[2] = "Descripción";
titColumna[3] = "Costo Prestación";
titColumna[4] = "Tipo Practica";
//Declaro una variable del tipo ArrayList para asignarle el metodo
List<Prestacion> prestaciones = Conexion.getInstance().getPrestacion();
Object[][] data = new String[prestaciones.size()][5];
try {
int ind = 0;
for (Prestacion prestacion : prestaciones) {
data[ind][0] = String.valueOf(prestacion.getCodigo());
data[ind][1] = prestacion.getNombre();
data[ind][2] = prestacion.getDescripcion();
data[ind][3] = String.valueOf(prestacion.getCostoPrestacion());
data[ind][4] = String.valueOf(prestacion.getTipoPractica());
ind++;
}
DefaultTableModel modelo = new DefaultTableModel(data, titColumna);
this.TablaPrestaciones.setModel(modelo);
} catch (Exception e) {
System.out.println("Error al cargar tabla" + e.getMessage());
}
}
Buenas,
Yo apuntaria un par de detalles tecnicos.
-Utiliza preparedstatements, con los que puedes construir las consultas de forma mas sencilla y robusta que uniendo strings y es mucho mejor practica de cara a la seguridad.
http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html
-En el codigo posteado se ve que abres conexiones pero nunca las cierras.
Un saludo
En aplicaciones de escritorio es muy frecuente abrir una única conexión en cuanto se necesita, y que permanezca abierta hasta que se cierra la aplicación.
Este es un ejemplo que crea la conexión, y la proporciona a las clases JDBC. Permanece abierta mientras la aplicación esté activa.
Cuando se cierra la aplicación, se realiza un shutdown ordenado de la base de datos.
public enum DBConnection {
INSTANCE;
private static volatile Connection connection;
private static boolean isDown;
static {
try {
connection = DriverManager.getConnection("jdbc:hsqldb:file:" + System.getProperty("user.dir") + "/dbfiles/jplaydb", "jplay", "jplay");
} catch (SQLException ex) {
JPToolsLogger.getRollingFileLogger().error(ex, ex.getMessage());
}
}
public static Connection getConnection() {
if (isDown) {
throw new IllegalStateException("connection is not opened");
}
return connection;
}
public static void shutdownConnection() {
if (connection != null) {
isDown = true;
try (PreparedStatement shutdownStatement = connection.prepareStatement("SHUTDOWN")) {
shutdownStatement.execute();
connection.close();
} catch (SQLException ex) {
JPToolsLogger.getRollingFileLogger().error(ex, ex.getMessage());
}
}
}
}
Buenas,
Si, en tu ejemplo es un singleton que entiendo se invoca desde el propio main para abrir la conexion y se llama al shutdown cuando se detecta la senal de cierre de la aplicacion.
Sin embargo en el codigo de este post veo que se llama al metodo AbrirConexion para todos los metodos que acceden a la base de datos y me pregunto si no se estaran creando varias conexiones simultaneas.
Por cierto choces, el codigo de jplay se puede consultar? lo tienes subido a algun repositorio?
Un saludo
Perdon, acabo de ver que la conexion se crea en el bloque static directamente ;-)
No sé qué hace ese método AbrirConexion. Espero que no abra una conexión cada vez que se invoca.
En realidad, mi ejemplo no necesita que se le llame desde main explícitamente. En la primera invocación del método getConnection() se ejecuta el constructor static, y queda inicializada y disponible la instancia connection para invocaciones futuras.
El código está en Bitbucket, pero en un repo privado de momento, puesto que estoy reconstruyendo toda la aplicación: el reproductor está "desmantelado", y estoy haciendo una refactorización en profundidad. Lo tuve olvidado durante varios meses, en otro repo, a causa de un "proyecto" en Latinoamérica (que prefiero olvidar cuanto antes), y lo he vuelto a retomar actualizando el código a JavaSE 8.
Creo que en pocas semanas estará "presentable" :) Ya te lo haré saber.
He convertido a públicos dos repos. Solo son librerías genéricas, pero pueden servir para "ver código" :)
https://bitbucket.org/choces/jptools
https://bitbucket.org/choces/wrappers
Esta segunda suite solo contiene wrappers de librerías externas.
Hola de nuevo, solucione el problema anterior, gracias por su ayuda.
Lo que ahora me pasa es que uno de los ABM que tengo debo registrar un tratamiento, el mismo tiene un atributo que es el tipo de practica, por ejem: el tratamiento es "ficha tecnica" y el tipo de practica es "Consulta". Como les comente la base de dato esta hecha en SQL(tengo relacionadas estas dos tablas, Tratamiento y TipoPractica). el incoveniente es que nosé, si el problema que me da, es por el codigo en Java o por las tablas en Sql.
Resulta que la insercion esta bien, es decir, carga el tratamiento nuevo, el problema es que cuando muestro los datos, (use un Jtable), en donde deberia mostrar el tipo de practica, en su lugar, muestra el numero 1, que es el codigo de la practica "consulta", es decir, como que siempre en el tipo de practica, muestra solo el 1, por mas que yo registre otros tratamiento con otros tipos de practica, siempre me muestra ese mismo valor. Me dijeron que es un problema de asociacion de datos, pero no tengo idea de como solucionarlo, estoy revisando el codigo en Java, pero para mi esta bien, va, las pocas veces que hice ABM, siempre los hice de la misma forma.
Espero que me hayan entendido, y me puedan ayudar, Sino les mandaria el codigo de lo que hice.
Gracias