## Insertar y Borrar Filas Programáticamente

En la sección anterior hemos visto cómo modificar el valor de una columna utilizando métodos del API JDBC 2.0 en vez de utilizar comandos SQL. Con el API JDBC 2.0 también podemos insertar una fila en una tabla o borrar una fila existente programáticamente.

Supongamos que nuestro propietario del café ha obtenido una nueva variedad de café de uno de sus suministradores. El "High Ground", y quiere añadirlo a su base de datos. Utilizando el API JDBC 1,0 podría escribir el código que pasa una sentencia insert de SQL al controlador de la báse de datos. El siguiente fragmento de código, en el que stmt es un objeto Statement, muestra esta aproximación:

    stmt.executeUpdate("INSERT INTO COFFEES " +
    		   "VALUES ('Kona', 150, 10.99, 0, 0)");

Se puede hacer esto mismo sin comandos SQL utilizando los métodos de ResultSet del API JDBC 2.0. Básicamente, después de tener un objeto ResultSet con los resultados de la tabla COFFEES, podemos constuir una nueva fila insertándola tanto en la hoja de resultados como en la tabla COFFEES en un sólo paso. Se construye una nueva fila en una llamada "fila de inserción", una fila especial asociada con cada objeto ResultSet. Esta fila realmente no forma parte de la hoja de resultados; podemos pensar en ella como un buffer separado en el que componer una nueva fila.

El primer paso será mover el cursor a la fila de inserción, lo que podemos hacer llamando al método moveToInsertRow. El siguiente paso será seleccionar un valor para cada columna de la fila. Hacemos esto llamando a los métodos updateXXX apropiados para cada valor. Observa que estos son los mismos métodos updateXXX utilizados en la página anterior para cambiar el valor de una columna. Finalmente, podemos llamar al método insertRow para insertar la fila que hemos rellenado en la hoja de resultados. Este único método inserta la fila simultáneamente tanto en el objeto ResultSet como en la tabla de la base de datos de la que la hoja de datos fue seleccionada.

El siguiente fragmento de código crea un objeto ResultSet actualizable y desplazable, uprs, que contiene todas las filas y columnas de la tabla COFFEES:

    Connection con = DriverManager.getConnection("jdbc:mySubprotocol:mySubName");
    Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
    				     ResultSet.CONCUR_UPDATABLE);
    ResultSet uprs = stmt.executeQuery("SELECT * FROM COFFEES");

El siguiente fragmento de código utiliza el objeto ResultSet, uprs para insertar la fila para "kona", mostrada en el ejemplo SQL. Mueve el cursor a la fila de inserción, selecciona los cinco valores de columna e inserta la fila dentro de uprs y COFFEES:

    uprs.moveToInsertRow();
    uprs.updateString("COF_NAME", "Kona");
    uprs.updateInt("SUP_ID", 150);
    uprs.updateFloat("PRICE", 10.99);
    uprs.updateInt("SALES", 0);
    uprs.updateInt("TOTAL", 0);
    uprs.insertRow();

Como podemos utilizar el nombre o el número de la columna para indicar la columna seleccionada, nuestro código para seleccionar los valores de columna se podría parecer a esto:

    uprs.updateString(1, "Kona");
    uprs.updateInt(2, 150);
    uprs.updateFloat(3, 10.99);
    uprs.updateInt(4, 0);
    uprs.updateInt(5, 0);

Podríamos habernos preguntado por qué los métodos updateXXX parecen tener un comportamiento distinto a como lo hacían en los ejemplos de actualización. En aquellos ejemplos, el valor seleccionado con un método updateXXX reemplazaba inmediatamente el valor de la columna en la hoja de resultados. Esto era porque el cursor estaba sobre una fila de la hoja de resultados. Cuando el cursor está sobre la fila de inserción, el valor seleccionado con un método updateXXX también es automáticamente seleccionado, pero lo es en la fila de inserción y no en la propia hoja de resultados. Tanto en actualizaciones como en inserciones, llamar a los métodos updateXXX no afectan a la tabla de la base de datos. Se debe llamar al método updateRow para hacer que las actualizaciones ocurran en la base de datos. Para el inserciones, el método insertRow inserta la nueva fila en la hoja de resultados y en la base de datos al mismo tiempo.

Podríamos preguntarnos que sucedería si insertáramos una fila pero sin suministrar los valores para cada columna. Si no suministramos valores para una columna que estaba definida para aceptar valores NULL de SQL, el valor asignado a esa columna es NULL. Si la columna no acepta valores null, obtendremos una SQLException. Esto también es cierto si falta una columna de la tabla en nuestro objeto ResultSet. En el ejemplo anterior, la petición era SELECT * FROM COFFEES, lo que producía una hoja de resultados con todas las columnas y todas las filas. Cuando queremos insertar una o más filas, nuestra petición no tiene porque seleccionar todas las filas, pero sí todas las columnas. Especialmente si nuestra tabla tiene cientos o miles de filas, querremos utilizar una claúsula WHERE para límitar el número de filas devueltas por la sentencia SELECT.

Después de haber llamado al método insertRow, podemos construir otra fila, o podemos mover el cursor de nuevo a la hoja de resultados. Por ejemplo, podemos, llamar a cualquier método que ponga el cursor en una fila específica, como first, last, beforeFirst, afterLast, y absolute. También podemos utilizar los métodos previous, relative, y moveToCurrentRow. Observa que sólo podemos llamar a moveToCurrentRow cuando el cursor está en la fila de inserción.

Cuando llamamos al método moveToInsertRow, la hoja de resultados graba la fila en la que se encontraba el cursor, que por definición es la fila actual. Como consecuencia, el método moveToCurrentRow puede mover el cursor desde la fila de inserción a la fila en la que se encontraba anteriormente. Esto también explica porque podemos utilizar los métodos previous y relative, que requieren movimientos relativos a la fila actual.

Ozito