Escolar Documentos
Profissional Documentos
Cultura Documentos
Los modelos de objetos de acceso a datos tradicionales se basan en establecer una conexión con la base de datos y mantener abierta
dicha conexión mientras la aplicación realiza diferentes operaciones con los datos.
Esta solución requiere en muchos casos mantener conexiones abiertas durante mucho tiempo y baja el rendimiento de la aplicación y
aumenta la posibilidad que otros usuarios no puedan acceder a la base de datos (número limitado de conexiones concurrentes).
Para solucionar el problema, ADO ofrece un concepto de acceso a los datos, consistente en la posibilidad de trabajar con estos en
modo desconectado.
Se basa en establecer una conexión con la base de datos para obtener una copia de la información almacenada y cerrar
inmediatamente la conexión, trabajando la aplicación con la copia de los datos en vez de con la información real.
En ADO.NET nos encontramos con clases específicas para trabajar en modo desconectado, proporcionando además la posibilidad de
actualizar el origen de datos con los cambios realizados sobre la copia local.
Hay que recordar que ADO no solo se utiliza para acceder a bases de datos relacionales, sino también para manipular documentos
XML.
Proveedores de datos
Son conjuntos de objetos adatados para trabajar con un origen de datos específico.
Ado incluye varios proveedores de datos para trabajar con las bases de datos más ampliamente utilizadas.
1. Proveedor Sql Server. Representa el conjunto de clases específicamente creadas para trabajar con bases de datos de Sql
Server tanto versión 2000 como 2005. estas clases se encuentran en el espacio de nombres System.Data.SqlClient
2. Proveedor de Oracle. Permiten trabajar contra bases de datos de Oracle, a partir de la versión 8i. Se encuentran en el espacio
de nombres System.Data.OracleClient
3. Proveedor genérico. También conocido como proveedor Ole DB, ofrece acceso a bases de datos para las que disponga de un
driver Ole DB. Se utiliza cuando no se dispone de un proveedor específico para un determinado tipo de base de datos. OleDb
ya es algo antiguo.
4. Proveedor ODBC. Similar al anterior. Acceso a través de un driver ODBC, tecnología aun mas antigua que OLE DB. Se
puede acceder a prácticamente todos los tipos de bases de datos existentes.
Clases Ado.NET
Aunque hay varios proveedores, todas las clases trabajan de la misma forma y disponen prácticamente de los mismos métodos y
propiedades.
Las características más importantes de cada una de las clases son:
• Connection. Permite establecer una conexión con la base de datos. Los objetos Connection representan conexiones activas
con la base de datos y deben permanecer abiertas para poder transferir información entre esta y la aplicación
• Command. Permiten enviar consultar SQL a la base de datos a través de la conexión. También se puede usar para ejecutar
procedimientos almacenados de la base de datos.
• DataReader. Cuando una consulta SQL o procedimiento almacenado devuelve resultados (caso instrucciones SQL de tipo
Select), el acceso a los registros afectados se realiza a través de un objeto DataReader.
• Parameter. Contiene información relativa a un parámetro que se envía al a base de datos durante la ejecución de un
procedimiento almacenado.
• Transaction. Permite agrupar operaciones sobre la base d datos dentro de una transacción, para que sean consideradas
conjuntamente como una única unidad de ejecución.
Ejemplo.
String cadenaCon;
cadenaCon=”Data Source=(local);”;
cadenaCon+=”Initial Catalog=basededatos;”;
cadenaCon+=”Integrated Security=True”;
SqlConnection cn= new SqlConnection(cadenaCon);
Apertura de conexión
Una vez creado el objeto Connection debemos proceder a abrir la conexión, usando el método Open()
Cn.Open();
String cadenaSql;
cadenaSql=”Insert into clientes”;
cadenaSql+=”values”+
“(‘miuser’,’mipasswd’,’mimail@hotmail.com’, ‘33444’)”;
SqlCommand cmd = new SqlCommand (cadenaSql, cn);
Ejecución de la consulta.
La clase Command dispone de los siguientes métodos:
ExecuteNonQuery(). Se utiliza para ejecutar consultas de acción que no devuelven resultados, como Insert, Update, Delete
ExecuteReader(). Se usa para ejecutar consultas de selección de registros (Select) como resultado devuelve un objeto DataReader que
permite acceder a los datos de la consulta.
tras ejecutarla, si queremos usar le mismo objeto Command para ejecutar otra nueva consulta sobre la base de datos no tenemos más
que asignar una nueva instrucción SQL a la propiedad CommandText del objeto.
cmd.CommandText=”Update….”;
tras esto, volvemos a invocar al método ExecuteNonQuery() o ExecuteReader() según proceda.
En caso de consultas de acción, no habría que realizar ningún tipo de manipulación de resultados, por lo que pasamos al cierre de la
conexión
Cn.Close();
Practica1. Creamos una base de datos en Sql con las siguientes tablas.
Tabla Clientes
Usuario nvarchar(50)
Password nvarchar(50)
Email nvarchar(100)
Telefono nvarchar(50)
Tabla temas
idTema int
tema nvarchar(50)
Tabla ventas
Idventa int
idLibro int
cliente nvarchar(100)
fecha smalldatetime
Solución.
protected void Button1_Click(object sender, EventArgs e)
{
String cadenaCon;
String cadenaSql;
SqlConnection cn;
SqlCommand cmd;
cadenaCon = "cadena a tu gusto";
cadenaSql = "Insert into clientes values ('" + TextBox1.Text + "',";
cadenaSql+="'"+TextBox2.Text+"'";
cadenaSql+="'"+TextBox3.Text+"'";
cadenaSql+="'"+TextBox4.Text+"')";
cn = new SqlConnection(cadenaCon);
try
{
cn.Open();
cmd = new SqlCommand(cadenaSql, cn);
cmd.ExecuteNonQuery();
Label1.Text = "el usuario se ha registrado correctamente";
}
catch (Excepcion es)
{
Label1.Text = "error en el registro" + exception.Message;
}
finally {
cn.Close();
}
}
}
Manipulación de resultados
Si la instrucción enviada desde la aplicación a la base de datos es de tipo Select, el método ExecuteReader() del objeto Command
devolverá un objeto de tipo DataReader que permitirá a la aplicación acceder a los registros resultantes de la consulta.
Las instrucciones que obtienen un objeto DataReader con el que tenemos acceso a los registros de la tabla libros serían:
El objeto DataReader ofrece una especie de cursor que permite acceder de forma individual a cada registro del conjunto.
Dicho cursor solo permite desplazamientos hacia delante en modo de solo lectura.
En el momento en que se produce la creación del objeto DataReader, el cursor se encuentra apuntando a la posición anterior al primer
registro del conjunto.
Para acceder a los datos del conjugo de registros a través del objeto DataReader, podemos usar sus propiedades y sus métodos.
Read(). Este método realiza un desplazamiento del cursor hacia delante, pasando a apuntar al siguiente registro del conjunto. Como
resultado devuelve un valor de tipo bool para indicarnos si el nuevo registro apuntado pertenece al conjunto (true) o si por el contrario
el cursor se ha salido del mismo (false).
Este bucle nos garantiza un recorrido por todos los registros indicados en la instrucción Select, desde el primero hasta el ultimo.
While (dr.Read())
{
//instrucciones que se ejecutan por todos los registros obtenidos de la instrucción Select
}
Al registro apuntado en cada momento por el cursor se le conoce como registro activo.
Item[String name]. Propiedad de tipo iniziador que permite recuperar, para el registro apuntado por el cursor, el valor del campo cuyo
nombre se especifica. El valor devuelto es tipo Object, debiendo convertirse mediante una operación de casting al valor original con el
que esta definido en la base de datos.
Para recuperar el valor del campo título del registro activo en el DataReader del ejemplo anterior seria
String t=(String)dr[“titulo”];
GetXxx(String name). Xxx representa el nombre de cada uno de los tipos simples de C#. son métodos que recuperan para el registro
activo el valor del campo cuyo nombre se especificado, sol oque, aquí, cada método devuelve el valor en el tipo especificado en Xxx.
Estos métodos no hacen conversiones implícitas, por lo que si el campo precio está en entero no puede aplicarse el método
GetDouble() para recuperar el valor.
IsDBNull(int pos). Devuelve un valor d tipo bool que nos dice si el valor del campo cuya posición se especifica para el registro actual
es null(true)
Ejemplo.
Código que permita mostrar en un Label los nombres de todos los libros.
String cadenaSql;
cadenaSql = “Select * from libros”;
SqlCommand cmd= new SqlCommand(cadenaSql, cn);
SqlDataReader dr = cmd.ExecuteReader();
While(dr.Read())
{
Label1.Text+=dr[“titulo”].ToString()+”<br/>”;
}
Login.aspx
}
catch (Excepcion ex)
{
Label1.Text = ex.Message;
}
finally
{
cn.Close();
}
}
}
Libros.aspx
protected void Button1_Click(object sender, EventArgs e)
{
String cadenaCon;
String cadenaSql;
SqlConnection cn;
SqlCommand cmd;
SqlDataReader dr;
cadenaCon = "cadena a tu gusto";
cadenaSql = "Select * from from Libros";
cn = new SqlConnection(cadenaCon);
try
{
cn.Open();
cmd = new SqlCommand(cadenaSql, cn);
dr = cmd.ExecuteReader();
Label1.Text=
"<table align='center' windth='60%' border='1'>";
Label1.Text+="<tr><th>Libro</th>";
Label1.Text+="<th>Precio</th>";
Label1.Text+="<th>Autor</th></tr>";
while(dr.Read())
Create Procedure actualizaPrecios @codigo int, @precio Money, @result int output
AS
SELECT @result = count(*) FROM libros WHERE idLibro=@codigo
If @result>0
UPDATE libros SET precio=@precio WHERE idlibro=@codigo
GO
Para ejecutar un procedimiento almacenado, al igual que en las consultas estándares, se realiza a través del objeto Command.
Establecimiento de parámetros
El procedimiento almacenado puede aceptar parámetros. Estos deben ser creados como objetos Parameter en la aplicación Ado y
añadimos a la colección de parámetros del objeto Command antes de proceder a la ejecución del procedimiento almacenado.
Por cada parámetro a pasar al procedimiento hay que crear un objeto Parameter correspondiente.
SqlParameter(String name, Object value);
Name es el nombre que tiene asignado el parámetro dentro del procedimiento almacenado y value es el valor que se le va a pasar en la
llamada.
Los parámetros de salida es un parámetro utilizado por el procedimiento para almacenar un resultado que después pude ser consultado
en el punto de llamada.
Los parámetros de salida se configuran usando el constructor por defecto de la clase Parameter, puesto que estos parámetros no tienen
por qué tener un valor.
Solución.
protected void Button1_Click(object sender, EventArgs e)
{
String cadenaCon;
String cadenaSql;
SqlConnection cn;
SqlCommand cmd;
SqlParameter sp;
cadenaCon = "cadena a tu gusto";
cadenaSql = "actualizaPrecios";
cn = new SqlConnection(cadenaCon);
try
{
cn.Open();
cmd = new SqlCommand(cadenaSql, cn);
cmd.CommandType=CommandType.StoredProcedure;
//creamos los parametros de entrada
//y los añadimos a la colección en la misma instrucción
cmd.Parameters.Add(new SqlParameter("@codigo", int.Parse(TextBox1.Text)));
cmd.Parameters.Add(new SqlParameter("@precio", decimal.Parse(TextBox2.Text)));
//el parametro de salida se configura aparte
sp= new SqlParameter();
sp.ParameterName="@result";
sp.SqlDbType=SqlDbType.Int;
sp.Direction=ParameterDirection.Output;
cmd.Parameters.Add(sp);
//ejecucion del procedimiento
cmd.ExecuteNonQuery();
if(int.Parse(sp.Value.ToString())>0)
{
Label1.Text="precio actualizado";
}
else
{
Label1.Text="no existe ningun libro con ese codigo";
}
}
Ventajas.
1. Acceso a datos en diferentes métodos. Si la aplicación necesita acceder a un determinado conjunto de registros desde
distintas página de la misma o tiene que operar con ellos en diferentes momentos durante su ejecución, así evitamos tener
que conectar repetidamente. Después, las modificaciones realizadas sobre la copia podrán ser actualizadas en cascada sobre
la base de datos.
2. Recorrido de los registros. A diferencia de un DataReader que solo permite acceso a datos en modo lectura y solo avance, la
información contenida en un DataSet puede ser modificada y sus filas se pueden recorrer en cualquier dirección.
3. Separación entre lógica y presentación. La utilización de copias de datos facilita la separación por capas de la aplicación. La
capa de lógica se encargaría de obtener las copias de los registros y de entregarlas a las páginas aspx para su presentación,
ocultándole a estas los detalles relativos a la obtención y actualización de la información en la base de datos.
Inconvenientes.
1. Datos en tiempo real. Al crear copia, dicha copia está ya desactualizada.
2. Entornos multiusuario. Errores de concurrencia en entornos de varios usuarios.
Clases Ado.Net
La clases para trabajar en modo desconectado se encuentran en el espacio de nombres System.Data.
Las copias de datos son independientes del proveedor, por lo que se utilizan las mismas clases para manipular cualquier tipo de origen
de datos.
DataAdapter – DataSet (DataTable- DataRelation – DataView)
DataTable (DataRow – DataColumn)
• DataSet. La clase más importante para manipular datos en modo desconectado. Los objetos dataset son los encargados de
albergar las copias de los datos, proporcionando todo lo necesario para poder realizar la manipulación de los mismos.
• DataTable. La información almacenada en un DataSet se organiza en tablas, cada una de las cuales se representan por un
objeto DataTable.
• DataRow. Los datos de un DataTable se organizan a su vez en filas y columnas. Cada fila de datos o registro es un objeto de
la clase DataRow.
• DataColumn. Este tipo de objetos dan información sobre los campos del DataTable, como tipo de datos que almacenan,
nombres de campos…
• DataView. Representa una vista de parte de los datos de un DataTable.
• DataAdapter. Se encargan de generar las copias de los datos, así como de llevar a cabo la actualización de la base de datos
con las modificaciones realizadas en las copias. Al ser un objeto que hace de interfaz entre el DataSet y la base de datos, cada
proveedor deberá ofrecer su propia clase DataAdapter.
Recorrido de un DataTable
La información de un DataTable se organiza en filas, cada fila es un objeto DataRow al que se accede mediante la propiedad Rows
del objeto DataTable.
Para recorrer la colección de objetos DataRow de una tabla:
La colección Rows dispone de la propiedad Count que nos da el número de filas existentes en la copia, además de un indicador para
acceder individualmente cada una de ellas a partir de su posición.
Cada objeto DataRow contiene la colección de campos de la fila, sirviendo la referencia a este objeto como indicador para acceder al
valor de cada campo a partir de su nombre o índice.
El valor de un campo es recuperado como Object, por lo que debe ser convertido al tipo original mediante una conversión explícita.
Ejemplo. Mostrar en una página Web el título de cada uno de los libros almacenados en el DataTable “totallibros”
DataRow[]Select(String where);
La llamada Select devuelve un array con los objetos DataRow de la tabla que cumplen la condición especificada en el parámetro.
Tendremos una página en donde el usuario podrá elegir un tema de la lista de temas posibles, después de haberse validado.
Tras elegir el tema, podrá ver el listado de los libros que tenga asociados.
La nueva página Temas.aspx será cargada con un DataSet que contiene una copia de los registros almacenados en la tabla de temas.
(lo ponemos en el load de la página)
Al seleccionar un tema, con un Linkbutton redireccionamos al usuario a la pagina Libros, pasándole en la URL el código del tema
elegido.
En la pagina Libros.aspx tendremos un instrucción Select que recupere solo los libros del tema elegido.
Temas.aspx
try
{
adp = new SqlDataAdapter(cadenaSql,cadenaCon);
adp.Fill(ds, "temaslibros");
foreach (DataRow dr in ds.Tables["temaslibros"].Rows)
{
//asignamos el nombre del tema como texto visible y el
//idTema como valor asociado
ListItem li = new ListItem(dr["tema"].ToString(), dr["idTema"].ToString());
DropDownList1.Items.Add(li);
}
}
Login.aspx
Si el usuario está registrado se redirecciona la página a Temas.aspx
If(dr.Read())
This.Response.Redirect(“Temas.aspx”);
Libros.aspx
Solo modificar la cadena Sql
Cada cadena de conexión se registra en el interior de <connectionStrings> a través del elemento <add> que debe especificar los datos
de los parámetros de conexión mediante los atributos:
name. Nombre del parámetro
providerName. Espacio de nombres del proveedor al que corresponde la cadena de conexión
connectionString. Cadena de conexión
<connectionStrings>
<clear/>
<add name="cadLibreria" providerName="System.Data.SqlClient" connectionString="Data Source=...;Initial Catalog=libreria;
Integrated Security=true;"/>
</connectionStrings>
ConnectionStringSettings configurarlibreria;
Configurarlibreria = ConfigurationManager.ConnectionStrings[“cadLibreria”];
La clase ConnectionStrings contiene una serie de propiedades que nos permiten acceder al resto de atributos del elemento add…
Para recuperar, pues en el código la cadena de conexión con la base de datos seria:
Modificación de un DataSet
Además de recorrer el contenido de un DataTable, un DataSet también nos permite alterar el contenido de sus tablas. Aunque estos
cambios se realizan en la copia local, es posible trasferirlos a la base de datos real.
Modificación de filas
Debemos asignar un nuevo valor al campo a través del objeto DataRow correspondiente a la fila que se quiere modificar.
Ejemplo
Para modificar el precio del segundo libro de la tabla “totallibros”:
ds.Tables[“totallibros”].Rows[1][“precio”]=24.7;
siendo ds la referencia al objeto DataSet que contiene la copia de los datos
1.Crear un nuevo ojbeto DataRow. Meidnate el método NewRow() de DataTable se crea un neuvo ojbeto DataRow vacío, con la
misma estructura de campos definida en el DataTable
DataRow dr;
dr = ds.Tables["totallibros"].NewRow();
2.Rellenar los campos. Se tiene que reinar caa uno delos campos de la nueva fila (excepto los autonuméricos)
dr = ds.Tables["totallibros"].NewRow();
dr["titulo"] = "titulo del libro1";
dr["idTema"] = 3;
dr["precio"] = 31.8;
dr["autor"] = "Pepe Lopez";
3.Agregar la nueva fila a la colección. Se añade el nuevo ojbeto DataRow creado a la colección de filas del DataTable.
ds.Tables["totallibros"].Rows.Add(dr);
ds.Tables["totallibros"].Rows[0].Delete();
la final no se elimina fisicamente de la colección, pero si intentamos acceder a su contenido una vez que se ha marcado como
eliminada se producirá una excepción, lo que deberá ser tenido en cuenta por el código. Ahora después veremos como se puede
consultar el estado de una fila.
asi es valido en la myori de los casos, pero en alguna ocasión hay que modficar manualmente las propiedades Command del
DataAdapter como en el caso de modificar, eliminar o insertar a traves de procedimientos almacenados.
2.Ejecución de la actualización
Tras configurar los comandos podemos realizar la actuailización invocando al método Update() del objeto DataAdapter. Se puede
utilizar los siguientes formatos:
Update(DataTable tabla). Actualiza la base de datos con la información del DataTable especificado
Update(DataSet data, String nombretabla). Actualiza la base con al información del DataTable cuyo nombre se indica en el segundo
parámetro y que está incluido en el DataSet data.
Update(DataRow[]filas). Actualiza la base co los cambios realizados en el array de objetos DataRow especificados
Ejemplo. Usando adp (referencia DataAdapter) actyakuzar kis canbuis reakuzadis eb ek DataTabke “totallibros” incluido en el
DataSet ds.
adp.Update(ds.Tables["totallibros"]);