Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
DataWhat?
En cuanto comienzas a trabajar con ADO.NET vers un montn de clases con nombres similares: DataReader, DataAdapter, DataSet, DataTable, DataRow, DataRowView, DataCongal bueno ese ltimo quiz no sea real, pero el resto de las clases s existen y debes conocerlas si quieres utilizar tus DataDatos en tu DataAplicacin. Est bueno pues, ya fueron suficientes DataPayasadas. Pero antes de meternos en ese tema, hay otros dos objetos que son ms primitivos y que permiten que te conectes e interactes con una base de datos: Connection y Command.
Connection permite que entables un canal de comunicacin con tu base de datos, y Command permite que ejecutes alguna instruccin sobre el motor de la base de datos, por ejemplo un query SQL de SELECT, INSERT, UPDATE o DELETE, o ejecutar un Stored Procedure.
La clase exacta que utilizars para establecer tu conexin y comandos depender del proveedor de datos que utilices, y el proveedor depender del tipo de base de datos a la que te quieras conectar: SQL Server, Oracle, Access, MySQL, etctera. Y aunque hay una forma en el .NET Framework 2.0 de hacer tu cdigo independiente del proveedor de base de datos, no hay que mezclar el caldo con la sopa todava; lo veremos en otro artculo. Por ahora, si quieres interactuar con una base de datos SQL Server, tendrs que utilizar SqlConnection y SqlCommand; si quieres platicar con Oracle tendrs que usar OracleConnection y OracleCommand; y si quieres hacerlo con Access, puedes usar OleDbConnection y OleDbCommand. Sin importar cul selecciones, los pasos para utilizarlo siempre son los mismos: 1. Abres la conexin 2. Haces tu desmadre (o sea, ejecutas tus comandos) 3. Cierras la conexin Usando SQL Server sera algo como esto:
// asumiendo que al principio se declar // using System.Data.SqlClient; // para usar ms fcilmente clases del SQL Server Data Provider SqlConnection miConexion = new SqlConnection("MiStringDeConexion"); miConexion.Open(); // Hago mis cosas miConexion.Close();
La conexin requerir de un string de conexin, de acuerdo al proveedor de datos, para indicar a qu base de datos conectarse y con qu credenciales. Por ahora utilizar "MiStringDeConexin" para mostrar donde va ese valor. Una prctica muy recomendada para evitar que se nos olvide cerrar la conexin es utilizar la instruccin using de C# (VB 2005 tambin la tiene). Ojo: No es la misma que la que se utiliza para importar un espacio de nombres.
using (SqlConnection miConexion = new SqlConnection("MiStringDeConexion")) {
miConexion.Open(); // Hago mis cosas // using, automticamente invoca los finalizadores, Close() en este caso, // en cuanto se termina el scope de la instruccin. }
El comando en s se especifica utilizando la propiedad CommandText. Adems, puedes especificar el tipo del comando que ests ejecutando con la propiedad CommandType:
TextCualquier query, incuyendo comandos para manipular la base de datos (CREATE TABLE, DROP TABLE, etc.) StoredProcedurePara ejecutar un procedimiento almacenado. TableDirectPara leer una tabla completita. Este no es soportado por algunos proveedores de datos como el de SQL Server.
using (SqlConnection miConexion = new SqlConnection("MiStringDeConexion")) { miConexion.Open(); // // hago mis cosas: // SqlCommand cmd1 = new SqlCommand(); cmd1.Connection = miConexion; cmd1.CommandType = System.Data.CommandType.Text; cmd1.CommandText = "SELECT * FROM 'Peliculas'"; // no lo estamos ejecutando todavia SqlCommand cmd2 = new SqlCommand(); cmd2.Connection = miConexion; cmd2.CommandType = System.Data.CommandType.StoredProcedure; cmd2.CommandText = "SelectPeliculas"; // nombre de mi SP en mi DB // falta ejecutarlo } // using manda llamar miConexion.Close()
ExecuteNonQuery()Para cuando tu instruccin no regresa una respuesta, p. ej. un INSERT, UPDATE o DELETE ExecuteScalar()Para cuando tu instruccin regresa UN SOLO registro con UN SOLO campo con un valor numrico, por ejemplo el resultado de un SELECT COUNT(*) FROM MiTabla ExecuteReader()Para cuando quieres leer el resultado de uno o varios SELECTs usando un DataReader.
// la prctica recomendada es alamacenar este string de conexin // en el archivo .config de mi aplicacin (web.config o app.config). // // en este ejemplo, me estoy conectando a la instancia local // SQLEXPRESS, a una base de datos llamada AdoNetDemo utilizando // las credenciales del usuario que ejecuta mi aplicacin string miStringDeConexion = @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" + "Integrated Security=True"; using (SqlConnection miConexion = new SqlConnection(miStringDeConexion)) { miConexion.Open(); // un INSERT utilizando SQL int registrosAfectados = 0;
string miQuery = "INSERT INTO Peliculas (Titulo, FechaDeAdquisicion, Precio) " + "VALUES ('El Santo y Blue Demon vs. las Vampiras','2006-08-06',15.65);"; SqlCommand cmd = new SqlCommand(miQuery, miConexion); cmd.CommandType = System.Data.CommandType.Text; registrosAfectados = cmd.ExecuteNonQuery(); // registrosAfectados ahora tiene valor de 1; // ahora un SELECT COUNT(*) usando SQL int numDeRegistros = 0; string otroQuery = "SELECT COUNT(*) FROM Peliculas;"; SqlCommand comandoParaContar = new SqlCommand(otroQuery, miConexion); numDeRegistros = Convert.ToInt32(comandoParaContar.ExecuteScalar()); // finalmente, un ejemplo de como leer todos los registros de una tabla SqlCommand miCommando = new SqlCommand("SELECT * FROM Peliculas;", miConexion); SqlDataReader speedy; speedy = miCommando.ExecuteReader(); } // using cerrar la conexin
Un momento! Ya sali el DataReader! Supongo entonces, que sera buena idea hablar de ellos.
DataReaders y DataSets
Cuando quieres leer datos, tienes de dos sopas en .NET: usar un DataReader o usar un DataSet con unDataAdaper. Para ambos necesitars una Connection y al menos un Command (para el SELECT), pero la diferencia est en qu puede hacer uno y qu puede hacer otro. DataReader es un objeto ligero y sper rpido que te permite leer UN registro a la vez, leyendo hacia enfrente solamente. Es lo que se conoce como un firehose reader, porque avienta los datos como si fuera una manguera a presin. En otras palabras DataReader es como Speedy Gonzles: chiquito, prieto y medio feo pero bien rpido el desgraciao.
Por otro lado, el DataSet es como Porky Pig: medio ghey y ms chonchoporque contiene algunos subobjetospero que puede hacer ms graciosadas. Con esos nos vamos a clavar en unos momentos ms (sin albur), pero primero vamos a ver el patrn clsico para utilizar un DataReader:
El mtodo Read() se encarga de leer los datos y al mismo tiempo, mover el cursor al siguiente registro. El mtodo regresa true si logr leer el siguiente o false si ya no hay ms registros que leer. A pesar de ser sencillo y eficiente, el DataReader tiene algunas desventajas como son:
Es solo-lectura. Si quieres actualizar datos tendras que ejecutar un Command por separado. No te dice informacin sobre los datos que ests leyendo, por lo que no solo tienes que conocer el tipo de datos que ests leyendo, sino el orden de las columnas. Suponiendo que tuviramos la siguiente tabla con la informacin de tu coleccin de pelculas:
As que si lo nico que necesitas es leer datos de manera eficiente, Speedy digo el DataReader es el que te conviene. Pero habr ocasiones en las que tengas que manipular varios datos a la vez, o necesites ver la relacin de datos entre varias tablas. Es ah cuando los DataSets y los DataTables son bastante tiles.
Un DataSet puede contener una o varias DataTable que representen datos de tu base de datos. Cada DataTable, tiene una coleccin de DataRows que representan los registros que fueron ledos. El papel del DataAdapter es el de sincronizador de datos por medio de sus dos mtodos principales, Fill() yUpdate(). La forma de trabajar sera: 1. Llenas tu DataSet 2. Haces tu desmadreactualizas, insertas, borras registros 3. Actualizas tu base de datos Una ventaja al usar un DataAdapter es que no tengo que preocuparme por andar abriendo y cerrando la conexin. Estos mtodos lo hacen automticamente. Con Fill() puedes llenar todo tu DataSeto una DataTable especfica de tu DataSetcon los datos de la base de datos. Para usarlo, debes primero configurarle al DataAdapter su SelectCommand, que es el que indica qu query debe ejecutar para traerse los datos. Si no planeas actualizar datos, pues este es el nico comando que necesitas configurarle.
// // // // // asumiendo que al principio se declar using System.Data.SqlClient; para usar ms fcilmente clases del SQL Server Data Provider y using System.Data; para usar DataSet, DataTable, DataRow, et. al.
string miStringDeConexion = @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" + "Integrated Security=True"; SqlConnection miConexion = new SqlConnection(miStringDeConexion); SqlCommand miCommando = new SqlCommand("SELECT * FROM Peliculas;", miConexion); SqlDataAdapter miAdaptador = new SqlDataAdapter(miCommando); // tambien habriamos podido utilizar la propiedad SelectCommand // miAdaptador.SelectCommand = miComando; DataSet porky = new DataSet(); // llenar mi DataSet de acuerdo al SelectCommand
miAdaptador.Fill(porky); // el DataAdapter automticamente cre un DataTable en mi DataSet // con la misma estructura que el resultado de mi query, // incluyendo nombres de columnas y tipos de datos // // ahora puedo leer los registros de la siguiente manera: foreach (DataRow registro in porky.Tables[0].Rows) { //registro["ID"]; //registro["Titulo"]; //registro["FechaDeAdquisicion"]; //registro["Precio"]; }
La manera ms sencilla de comprobar que mi DataSet o DataTable tiene ya datos es utilizando el visualizador que viene con Visual Studio:
Con Update() el DataAdapter intenta propagar los cambios que hayas hecho en tu DataSet hacia la base de datos. Cmo lo hace? Polvos de hada.
Bueno, en realidad usa una propiedad de cada DataRow llamada RowState, que puede tener valores como nuevo, sin cambios, modificado y eliminado. El estado de cada DataRow se ajusta en cuanto haces algn cambio a los datos. De esa forma lo nico que tiene que hacer el DataAdapter, cuando llamas Update() es recorrer todos los rows del DataSet e invocar el InsertCommand, UpdateCommand o DeleteCommand, de acuerdo a si el DataRow es nuevo, modificado o eliminado, respectivamente. Obviamente para que esto funcione, necesitas haberle configurado previamente esos comandos al DataAdapter. Aunque podras especificarlos manualmente, si quieres evitar la hueva errores al hacerlo, puedes utilizar unCommandBuilder, que automticamente los inferirel Insert, Update y DeleteCommanden base alSelectCommand.
string miStringDeConexion = @"Data Source=.\SQLEXPRESS;Initial Catalog=AdoNetDemo;" + "Integrated Security=True"; SqlConnection miConexion = new SqlConnection(miStringDeConexion); SqlCommand miCommandoSelect = new SqlCommand("SELECT * FROM Peliculas;", miConexion); SqlDataAdapter miAdaptador = new SqlDataAdapter(miCommandoSelect); SqlCommandBuilder miConstructor = new SqlCommandBuilder(miAdaptador); DataSet porky = new DataSet(); // llenar mi DataSet de acuerdo al SelectCommand miAdaptador.Fill(porky); // modificar algunos de los registros // al primer registro, ponerle el ttulo en maysculas porky.Tables[0].Rows[0]["Titulo"] = porky.Tables[0].Rows[0]["Titulo"].ToString().ToUpper(); // eliminar el 4to registro porky.Tables[0].Rows[3].Delete(); // actualizar la base de datos en base a los cambios // hasta antes este momento la BD sigue intacta miAdaptador.Update(porky); // los cambios fueron propagados a la BD.
Para ser un poco ms completos, hay que mencionar que DataSet tiene muchas ms moneras que no alcanzaremos a ver en este artculo. Por ejemplo, puede representar varias tablas de tu base de datos con todo y relaciones para mantener la integridad referencial.
En otras palabras, puedes representar toda o una parte de tu base de datos por medio de un DataSet. Sin embargo, cuando manejas varias tablas al mismo tiempo, las cosas comienzan a ponerse interesantes cuando quieres llenarlas o actualizarlas. Quiz es por eso que en Visual Studio 2005incluyendo las versiones Expressahora trae soporte paraTableAdapters, que ser el tema del prximo artculo en esta serie.
Este es el primero de varios artculos que tratan sobre ADO.NET y las moneras que trae la versin 2.0 del .NET Framework. Si quieres averiguar ms sobre el tema, haz una bsqueda en este blog o dale clic a la etiqueta de ado.net. Si tienes sugerencias, correcciones u opiniones sobre este artculo o si tienes sugerencias para artculos nuevos de temas que te gustara ver en este blog, deja un comentario mediante los enlaces de abajo. Las imgenes y nombres de los personajes "Speedy Gonzales" y "Porky Pig" son propieadad de Warner Bros. y tomados sin permiso para fines de no-lucro. As que si piensan demandarme, ni se molesten, porque saldra corriendo y gritando como Flanders para quitar las imgenes y referencias de este blog.