127.0.0.1: Hogar dulce hogar
Mostrando entradas con la etiqueta ado. Mostrar todas las entradas
Mostrando entradas con la etiqueta ado. Mostrar todas las entradas

jueves, 29 de julio de 2010

[ADO.NET] Transacciones con DataSet

Una vez que en el artículo anterior se mostró cómo se pueden obtener datos a través de ADO.NET, ahora es momento de comprobar cómo se pueden realizar operaciones con dichos datos.

Es necesario recordar el trabajo que puede suponer el realizar operaciones con diferentes consultas, en especial si la cantidad de lógica de negocio a representar es bastante grande y/o compleja. A través de DataSet y con el DataGridView vamos a comprobar lo sencillo que puede resultar agregar, borrar y actualizar datos sin necesidad de escribir todo ese código.

En primer lugar, partiremos del artículo anterior y veamos qué nos puede ofrecer el DataGridView:

image

Disponemos de varias casillas para marcar, en la que habilitamos la adición, edición y actualización de las filas, además de  poder reordenarlas a nuestro gusto. Esto simplemente significa que podemos una vez obtenidos los datos, hacer clic en cualquier fila y comenzar a editarlos. Evidentemente se disponen de eventos adecuados y sería responsabilidad del diseñador administrar este tipo de permisos para evitar efectos indeseados. Pero por ahora, vayamos al código. Del mismo modo que en antes tuvimos que crear una función que obtenga los datos y los inserte en un DataSet, ahora vamos a extraer el DataSet empleado en el DataGridView, que es el que hemos usado y vamos a actualizar todos los cambios que se hayan hecho en la BD:

   1: Conexion.AbreConexion();
   2: SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from Jugador", Conexion.Instancia);
   3: SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);
   4: dataAdapter.InsertCommand = commandBuilder.GetInsertCommand();
   5: dataAdapter.DeleteCommand = commandBuilder.GetDeleteCommand();
   6: dataAdapter.UpdateCommand = commandBuilder.GetUpdateCommand();
   7:  
   8: dataAdapter.Update(dataset, "Jugador");

En primer lugar creamos la selección (obtener todos los jugadores) y al DataAdapter le añadimos los sucesivos comandos que vamos a emplear a través del CommandBuilder. Por último, invocamos que se actualice la consulta efectuada con el DataAdapter con los datos del DataSet indicando además el nombre de la tabla de la BD. Con este código, ya tenemos resueltas las tres operaciones. Además, el DataSet incorpora flags en las filas para saber cuáles se han alterado (bien sea por adición, actualización o eliminación) de modo que no se realice transacción alguna por aquellas filas que no han sufrido cambios.

Por último, queda simplemente invocar la función anterior a través de la interfaz para que se ejecute. Disponemos de diversos modos, pudiendo usar por ejemplo los eventos de DataGridView que identifican los cambios en las filas modificadas o bien mediante un botón. En este caso emplearemos el botón, y en su evento OnClick tendremos el siguiente código:

   1: CAD.Equipo.ActulizarJugadores(dataset);

De modo que le pasemos el DataSet y así pueda actualizar los cambios. Vaya diferencia de código respecto al modo clásico, ¿no? Pues los siguiente artículos sobre Entity Framework serán acojonantes :)

[ADO.NET] Obtener datos con DataSet

Siguiendo con la línea de artículos de la parte de acceso a datos del .NET Framework, en el presente mostraré cómo se pueden obtener datos y trabajar con ellos a través de un DataSet. Nuestro objetivo primero será obtener los datos de los jugadores de todos los equipos. Para ello emplearemos un SqlDataAdapter a través del cual ejecutaremos la consulta SQL que deseemos y posteriormente con los datos obtenidos, rellenaremos un DataSet:

   1: DataSet jugadores = new DataSet();
   2:  
   3:             try
   4:             {
   5:                 Conexion.AbreConexion();
   6:                 SqlDataAdapter dataAdapter = new SqlDataAdapter("select * from Jugador", Conexion.Instancia);
   7:  
   8:                 dataAdapter.Fill(jugadores);
   9:                 jugadores.Tables[0].TableName = "Jugador";
  10:  
  11:             }

Una vez hemos rellenado nuestro DataSet, podemos ajustar varios parámetros, entre ellos el nombre de la tabla. Esto es importante porque podemos montar en un mismo DataSet varias tablas y relacionarlas entre ellas, por lo que es conveniente ajustar el nombre de las mismas de un modo que el programador les resulte familiar y sea acorde a la representación de datos con la que trabaja. En nuestro caso y al tener una única tabla, le asignaremos el nombre de “Jugador”.

Al ejecutar esta función, devolveremos el DataSet resultante de la consulta. ¿Y esto como se puede manejar en la interfaz? Usaremos la herramienta DataGridView:

image

Este control permite representar una tabla de filas y columnas. Se puede enlazar directamente con DataSets que podemos crear a través de un asistente al que podemos acceder a través del propio DataGridView cuando lo insertamos en una ventana:

image

En nuestro caso como ya tenemos el código que nos va a devolver el DataSet, nos olvidamos del asistente y creamos un objeto DataSet en la ventana que permita trabajar en modo desconectado con los datos proporcionados. Añadimos un botón para invocar a la función anterior y asignar el DataSet cargado a nuestro DataGridView:

   1: dataset = CAD.Equipo.ObtenerJugadores();
   2: dataGridView1.DataSource = dataset.Tables[0];

En este punto es importante recordar que DataSet no es una tabla ni una consulta, es una representación del estado de los datos obtenidos en su conjunto, por lo que debemos especificar qué tabla queremos mostrar. En este caso mostramos la primera tabla (puesto que tiene el índice 0) pero también hubiéramos podido obtener la tabla a través de su propio nombre:

   1: dataset = CAD.Equipo.ObtenerJugadores("fcb");
   2: dataGridView1.DataSource = dataset.Tables["Jugador"];

A partir de ejecutar dicho código, en nuestro DataGridView obtendremos exactamente las mismas columnas que tenemos en la tabla de Jugador en la BD. Todo esto se puede especificar, bien a través de la obtención de los datos o bien a través de personificar el DataGridView para que muestra sólo aquellas columnas que se requieran.

viernes, 16 de julio de 2010

[ADO.NET] DataSet

Siguiendo con el taller de ADO, ahora vamos a aplicar el potencia de una de las herramientas más importantes de la versión 2.0 de .NET Framework: El dataset.

Hasta ahora hemos estado viendo cómo acceder a los datos a través de entidades que permiten que permiten aplicar casi directamente los comandos de SQL sobre la base de datos. La opción propuesta por Microsoft desde .NET Framework como alternativa es el DataSet, que nos aporta las siguientes características:

Está diseñado para el acceso a datos independientemente del origen de datos e incluso se puede emplear con distintos orígenes al mismo tiempo. Además, es totalmente serializable con XML, lo que permite que esa muy apto para comunicar nuestro sistema con entidades externas.

Internamente el DataSet se componen de una colección de DataTable, formados por filas y columnas de datos junto con información propia de la tabla (identificador, nombre, claves principales, claves ajenas, etc)

En el diagrama siguiente se ilustra la relación entre un proveedor de datos de .NET Framework y un DataSet.

image

Y a continuación se muestra el modelo de datos del DataSet:

image

  • DataRelationCollection: Una colección de relaciones representadas por la entidad DataRelation. Enlaza una DataTable con otra a través de sus relaciones como si fuera una base de datos relacional. Estas relaciones pueden se pueden modificar y alterar en función de nuestras necesidades.
  • DataTableCollection: Una colección de DataTables. Cada tala tiene sus columnas ( DataColumnCollection), filas ( DataRowColletion ), restricciones ( Constraints ). Es de señalar algo muy importante que ocurre con las DataRow, que almacenan el estado original y actual de modo que puede detectar cambios en los valores almacenados.
  • ExtendedProperties: Como se apreciamos en el modelo de datos este componente se repite varias veces. ExtendedProperties no es más que un PropertyCollection en la que podemos colocar información personalizada, como por ejemplo la instrucción select que empleamos para generar los datos, la hora en que se generaron, etc.

En los próximos artículos pondré ejemplos de cómo trabajar con DataSets.

miércoles, 30 de junio de 2010

[ADO.NET] Hacer un Insert y no morir en el intento

Después de hacer una lectura de una base de datos, ¿qué mejor que hacer un Insert para demostrar nuestro poderoso dominio con la información? ADO.NET ofrece unas cuantas soluciones, de las cuales veremos una: empleando un SqlCommand.

Todos conocemos la instrucción Insert de SQL. Vale. Pues ya lo tenemos todo resuelto. Lo primero que tenemos que hacer es abrir la conexión y crear un string con el comando que queramos insertar. Después ejecutamos el comando, cerramos la conexión y asunto resuelto. Complicado, ¿verdad?

Aquí tenemos el código:

   1: string query = "INSERT INTO EQUIPO VALUES ('" + siglas + "','" + nombre + "')";
   2:  
   3: //usando un command builder, para evitar un sql injection como el siguiente:
   4: //insert into equipo values ('mer', 'merida fc'); delete from equipo where siglas='her';-- '');
   5:  
   6:        
   7: SqlCommand command = new SqlCommand(query, Conexion.Instancia);
   8:  
   9: if ( command.ExecuteNonQuery() == 1)
  10: {
  11:     ret = true;
  12: }

Como se aprecia, creamos un objeto SqlCommand con el string de la instrucción que queremos ejecutar (nótese que también podrían valer delete y update) junto con el SqlConnection. El SqlCommand tiene varios métodos de ejecución, entre ellos el ExecuteNonQuery que nos devuelve la cantidad de filas que se han modificado al ejecutar la instrucción. Sencilo e intuitivo, ¿verdad?

Pero lamentablemente, cada vez que alguien hace esto, Dios mata a un gatito. Esto es una muestra de una mala práctica, ya que no controla el fallo de SqlInjection. Este fallo consiste en algo normal y se produce por las siguiente causas:

  • Mal diseño: Tu capa de presentación no valida los datos.
  • Mal diseño: Tu capa de lógica no valida los datos.
  • Mal diseño: Tu aplicación provoca que se alteren datos que no debe.
  • Desastre: Borrar todo, seguridad?

En vista al código anterior, ¿que podríamos hacer en el código anterior? Un ejemplo bruto sería insertar en el campo del formulario el siguiente código:

   1: '); DELETE MASTER;

Lo cual la capa de datos, recibiría la siguiente cadena a ejecutar:

   1: INSERT INTO EQUIPO WHERE VALUES('');
   2: DELETE MASTER;
   3: ');

Sobran las palabras. ¿Qué soluciones dispone .NET para que esto no ocurra? El propio objeto SqlCommand. Anteriormente insertábamos como string toda la secuencia de comandos, con lo que la validación es muy compleja. Si en lugar de ello empleamos parámetros, estamos ganando en seguridad y estabilidad, además de la limpieza de código. La clase SqlCommand se encarga de validar los datos y evita que se pueda producir un SqlInjection. Veamos paso a paso cómo se hace:

   1: string query = "INSERT INTO EQUIPO VALUES (@siglas, @nombre)";
   2:  
   3: SqlCommand command = new SqlCommand(query, Conexion.Instancia);
   4: command.Parameters.Add(new SqlParameter("@siglas", siglas));
   5: command.Parameters.Add(new SqlParameter("@nombre", nombre));
   6:  
   7: if (command.ExecuteNonQuery() == 1)
   8: {
   9:     ret = true;
  10: }

A través del carácter @, indicamos que lo siguiente es un parámetro. Nótese que no importa siquiera el tipo de dato. Posteriormente, se crean los parámetros y se indexan internamente en el SqlCommand. Mediante SqlCommand.Parameters podemos acceder a ellos.

Como hemos visto, esto garantiza una cierta seguridad en el acceso a la BD de nuestra aplicación, además de aumentar la mantenibilidad del código y de la propia aplicación.

domingo, 2 de mayo de 2010

[ADO.NET] Lectura de una tabla

ADO.NET proporciona una serie de métodos diversos para acceder a la base de datos y realizar transacciones. En este artículo se mostrará cómo se pueden leer datos de una tabla. Previamente se parte de la base de que la parte de realizar una conexión ya es conocida y está implementada.

Uno de los métodos para acceder a la tabla es empleando proveedores de datos. Estos proveedores permiten conectarse a diferentes motores de base de datos (OJBC, Sql Server, MySQL, Oracle, etc) y ejecutar comandos SQL de la misma forma que si estuviésemos en el cliente del motor.

Para la lectura de una tabla, se proporciona al clase DataReader que únicamente permite leer los datos. A través de esa clase ejecutaremos un comando que hemos insertado previamente, desde el cuál indicaremos la orden de SQL correspondiente (si es de lectura, sólo puede ser una SELECT en principio). Por lo tanto, una vez abierta la conexión nos encontramos con el siguiente código:

string query = "SELECT nombre FROM EQUIPO";
SqlCommand command = new SqlCommand(query, Conexion.Instancia);

Al comando se le introduce la sentencia que se desea ejecutar junto con la conexión que previamente hemos abierto. En el código de arriba, suponemos que tenemos una clase singleton que gestiona toda la conexión y que el SqlConnection lo obtenemos a través de Conexion.Instancia. A continuación el siguiente paso es ejecutar el comando y obtener las filas que se han leído, para lo cual usaremos el DataReader:

SqlDataReader sqlDataReader = command.ExecuteReader();

El comando al ejecutarse devuelve un puntero a los datos leídos, como si fuera un simple fichero que se desea abrir. Por ello el dataReader incorpora unos métodos similares. Para obtener los datos, usaremos el siguiente método:

while (sqlDataReader.Read())
{
//sqlDataReader[0];
//sqlDataReader[1];
}

Con este bucle seguirá leyendo hasta que finalice la consulta. Para obtener los datos accedemos a las sucesivas posiciones de sqlDataReader, donde cada posición representa una columna leída. Es de señalar que devuelve tipo object, por lo que hay que hacer una conversión explícita al tipo deseado.

Por último no te olvides de cerrar la conexión :)

domingo, 25 de abril de 2010

[ADO.NET] Conexión con una base de datos

El pasado jueves 22 de Abril impartí el taller de ADO.NET en la Universidad de Alicante. Como últimamente dispongo de poco tiempo para sobrevivir -y menos para escribir artículos- comenzaré con esta temática, inaugurando la serie/tag de ADO en este blog. Uno de los puntos críticos de cualquier aplicación es el tratamiento de su persistencia de datos. En otra ocasión trataré el tema de la arquitectura, que es bastante interesante. Ahora simplemente lo voy a dedicar a ver cómo se puede acceder a los datos que previamente se han almacenado en una base de datos. ADO.NET proporciona una serie de clases llamadas proveedores que permiten realizar el tratamiento de datos con una BD. En este caso vamos a suponer que el motor de la base de datos es SQL Server 2005, aunque obviamente es perfectamente posible conectarse a otras bases de datos a través de sus respectivos proveedores de datos. Para conectarnos a nuestro motor de base de datos, debemos usar un string que actuará de cadena de conexión y una clase llamada SQLConnection que será la encargada gestionar la totalidad de la conexión. Por ejemplo, un string como cadena de conexión podría ser el siguiente:
string connectionString = "Data Source=localhost;Initial Catalog=TallerADO; integrated security=true";
En este caso tenemos varias propiedades. En primer lugar indicamos que el servicio del motor de la base de datos está situado en la dirección localhost y que vamos a emplear la base de datos cuyo nombre es TallerADO. Por último indicamos que tiene seguridad integrada, lo cual significa que usaremos la autenticación propia de Windows para acceder a dicho servicio. A continuación debemos instanciar la clase SQLConnection del siguiente modo:
SQLConnection conexion = new SqlConnection(connectionString);
Por último, abrirmos la conexión con:
conexion.Open()
y la cerramos con
conexion.Close()
Sin embargo, el usar un string como cadena de conexión puede resular bastante tedioso para el programador, en especial aquellas ocasiones en que la cadena es bastante larga y/o posee un gran número de atributos. Para ello existe una clase que ayuda a generar esta cadena, una clase llamada SqlConnectionStringBuilder. Esta clase proporciona propiedades de acceso para cada uno de los atributos que puede tener una cadena de conexión desde todos los que vimos anteriormente hasta otros como la caducidad de la conexión, timeout, usuario, contraseña, etc. Veamo cómo se hace:

SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();

builder.DataSource = "localhost";
builder.InitialCatalog = "TallerADO";
builder.IntegratedSecurity = false;
builder.UserID = "yuju";
builder.Password = "yuju";
conexion = new SqlConnection(builder.ConnectionString);
En este caso hemos añadido dos nuevas propiedades: userID y Password, que serán las credenciales que usaremos para conectarnos al motor de la base de datos. Como queremos usar esas credenciales, marcamos IntegritatedSecurity como false para evitar que al hacer la conexión se emplee la cuenta de Windows con tales fines. Por último, a través de la propiedad ConnectionString el builder nos proporciona la cadena generada. Mejor así, ¿no? Por último, se entiende que todo el código aquí mencionado debe ir dentro de try/catch para emplearse en el gestor de excepciones que tengamos en nuestra aplicación.