You are on page 1of 24

Curso de C#

Acceso a bases de datos con


ADO.NET

Bases de datos
Interfaces de acceso a bases de datos
Arquitectura ADO.NET
Clases ADO.NET
Transacciones en ADO.NET
Data Binding

Bases de datos
Cualquier aplicación de interés requiere el almacenamiento y posterior recuperación
de los datos con los que trabaje (pedidos en aplicaciones de comercio electrónico,
datos de personal para las aplicaciones de recursos humanos, datos de clientes en
sistemas CRM, etc.). Los sistemas de gestión de bases de datos (DBMSs) nos
permiten almacenar, visualizar y modificar datos, así como hacer copias de
seguridad y mantener la integridad de los datos, proporcionando una serie de
funciones que facilitan el desarrollo de nuevas aplicaciones.
Desde un punto de vista intuitivo, una base de datos no es más que un fondo
común de información almacenada en una computadora para que cualquier persona
o programa autorizado pueda acceder a ella, independientemente de su lugar de
procedencia y del uso que haga de ella. Algo más formalemente, una base de datos
es un conjunto de datos comunes a un "proyecto" que se almacenan sin
redundancia para ser útiles en diferentes aplicaciones.
El Sistema de Gestión de Bases de Datos (DBMS) es el software con capacidad para
definir, mantener y utilizar una base de datos. Un sistema de gestión de bases de
datos debe permitir definir estructuras de almacenamiento, así como acceder a los
datos de forma eficiente y segura. Ejemplos: Oracle, IBM DB2, Microsoft SQL
Server, Interbase...
En una base de datos, los datos se organizan independientemente de las
aplicaciones que los vayan a usar (independencia lógica) y de los ficheros en los
que vayan a almacenarse (independencia física). Además, los datos deben ser
accesibles a los usuarios de la manera más amigable posible, generalmente
mediante lenguajes de consulta como SQL o Query-by-example. Por otro lado, es
esencial que no exista redundancia (esto es, los datos no deben estar duplicados)
para evitar problemas de consistencia e integridad.
Bases de datos relacionales
• Tabla o relación: Colección de registros acerca de entidades de
un tipo específico (p.ej. alumnos).
• Atributo, campo o columna: Propiedad asociada a una
entidad (p.ej. nombre, apellidos...). Cada atributo tiene un tipo
asociado (p.ej. entero, cadena de caracteres...) y puede tomar
el valor nulo (null).
• Tupla, registro o fila: Datos relativos a un objeto distinguible
de otros (p.ej. un alumno concreto).
Se pueden estrablecer relaciones entre las tablas de una base de datos relacional
mediante el uso de claves primarias y claves externas (p.ej. cada libro tiene, al
menos, un autor).
• Clave primaria: Conjunto de atributos que nos permiten
identificar unívocamente a una entidad dentro de un conjunto de
entidades (p.ej. número de matrícula). La clave primaria
garantiza la unicidad de una tupla, pues no se permite la
existencia de varios registros que compartan su clave primaria.
• Clave externa: Conjunto de atributos que hacen referencia a
otra tabla, lo que nos permite establecer relaciones lógicas entre
distintas tablas. Los valores de los atributos de la clave externa
han de coincidir con los valores de los atributos de una clave
(usualmente la primaria) en una de las tuplas de la tabla a la
que se hace referencia (integridad referencial).

SQL
Lenguaje estándar para acceder a una base de datos relacional, estandarizado por
el American National Standards Institute (ANSI): SQL-92. En gran parte, los
distintos DBMS utilizan todos el mismo SQL, si bien cada vendedor le ha añadido
sus propias extensiones. El lenguaje SQL se divide en:
• DDL (Data Definition Language), utilizado para crear y modificar
la estructura de la base de datos (p.ej. CREATE TABLE).
• DML (Data Manipulation Language), empleado para manipular
los datos almacenados en la base de datos (p.ej. consultas con
la sentencia SELECT).
• DCL (Data Control Language), para establecer permisos de
acceso (GRANT, REVOKE, DENY) y gestionar transacciones
(COMMIT y ROLLBACK).

Interfaces de acceso a bases de datos


Evolución histórica de los "estándares" propuestos por Microsoft:
• ODBC (Open Database Connectivity): API estándar
ampliamente utilizado, disponible para múltiples DBMSs, utiliza
SQL para acceder a los datos.
• DAO (Data Access Objects): Interfaz para programar con
bases de datos JET/ISAM, utiliza automatización OLE y ActiveX.
• RDO (Remote Data Objects): Fuertemente acoplado a ODBC,
orientado al desarrollo de aplicaciones cliente/servidor.
• OLE DB: Construido sobre COM, permite acceder a bases de
datos tanto relacionales como no relacionales (no está
restringido a SQL). Se puede emplear con controladores ODBC y
proporciona un interfaz a bajo nivel en C++.
• ADO (ActiveX Data Objects): Ofrece un interfaz orientado a
objetos y proporciona un modelo de programación para OLE DB
accesible desde lenguajes distintos a C++ (p.ej. Visual Basic).

ADO se diseñó para su uso en arquitecturas cliente/servidor con bases de datos


relacionales (no jerárquicas, como es el caso de XML). Su diseño no está
demasiado bien factorizado (ya que existen muchas formas de hacer las cosas y
algunos objetos acaparan demasiadas funciones) y ADO no estaba pensado para
arquitecturas multicapa en entornos distribuidos.
ADO .NET es una colección de clases, interfaces, estructuras y tipos enumerados
que permiten acceder a los datos almacenados en una base de datos desde la
plataforma .NET. Si bien se puede considerar una versión mejorada de ADO, no
comparte con éste su jerarquía de clases (aunque sí su funcionalidad).
ADO .NET combina las capas ADO y OLE DB en una única capa de proveedores
(managed providers). Cada proveedor contiene un conjunto de clases que
implementan interfaces comunes para permitir el acceso uniforme a distintas
fuentes de datos. Ejemplos: ADO Managed Provider (da acceso a cualquier fuente
de datos OLE DB), SQL Server Managed Provider (específico para el DBMS de
Microsoft), Exchange Managed Provider (datos almacenados con Microsoft
Exchange)...
ADO .NET usa XML. De hecho, los conjuntos de datos se almacenan internamente
en XML, en vez de almacenarse en binario como sucedía en ADO. Al estar los datos
almacenados en XML, se simplifica el acceso a los datos a través de HTTP (algo que
ocasiona problemas en ADO si los datos tienen que pasar cortafuegos). Por otro
lado, se simplifica la comunicación entre aplicaciones al ser XML un formato
estándar (p.ej. comunicación con applets Java).
Con ADO .NET se puede acceder a los datos de dos formas distintas:
• Acceso conectado: Acceso sólo de lectura con cursores
unidireccionales ("firehose cursors"). La aplicación realiza una
consulta y lee los datos conforme los va procesando con la
ayuda de un objeto DataReader.
• Acceso desconectado: La aplicación ejecuta la consulta y
almacena los resultados de la misma para procesarlos después
accediendo a un objeto de tipo DataSet. De esta forma, se
minimiza el tiempo que permanece abierta la conexión con la
base de datos.
Al proporcionar conjuntos de datos de forma desconectada, se utilizan mejor los
recursos de los servidores y se pueden construir sisyemas más escalables que con
ADO (que mantenía abierta la conexión con la base de datos la mayor parte del
tiempo). Este enfoque resulta más adecuado en sistemas distribuidos como
Internet.

Arquitectura ADO.NET
El funcionamiento de ADO.NET se basa esencialmente en utilizar los siguientes
componentes:
• Data Provider (proveedor de datos): Proporciona un acceso
uniforme a conjuntos de datos (bases de datos relacionales o
información ID3 de ficheros MP3). Su papel el similar al de un
controlador ODBC o JDBC.
• DataSet: El componente más importante, puede almacenar
datos provenientes de múltiples consultas (esto es, múltiples
tablas).
• DataAdapter: Sirve de enlace entre el contenedor de conjuntos
de datos (DataSet) y la base de datos (Data Provider).
Los componentes anteriores se completan con DataReader (para realizae
eficientemente lecturas de grandes cantidades de datos que no caben en memoria),
DataRelation (la forma de establecer una reunión entre dos tablas), Connection
(utilizada por DataAdapter para conectarse a la base de datos) y Command (que
permite especificar las órdenes, generalmente en SQL, que nos permiten consultar
y modificar el contenido de la base de datos: select, insert, delete y update).
Un proveedor de datos debe proporcionar una implementación de Connection,
Command, DataAdapter y DataReader.
El modo de funcionamiento típico de ADO.NET es el siguiente:
• Se crean un objeto Connection especificando la cadena de
conexión.
• Se crea un DataAdapter.
• Se crea un objeto Command asociado al DataAdapter, con la
conexión adecuada y la sentencia SQL que haya de ejecutarse.
• Se crea un DataSet donde almacenar los datos.
• Se abre la conexión.
• Se rellena el DataSet con datos a través del DataAdapter.
• Se cierra la conexión.
• Se trabaja con los datos almacenados en el DataSet.
Como los conjuntos de datos se almacenan en memoria y trabaja con ellos de
forma desconectada, cuando hagamos cambios sobre ellos (inserciones, borrados o
actualizaciones) debemos actualizar el contenido de la base de datos llamando al
método Update del DataAdapter y, posteriormente, confirmar los cambios
realizados en el DataSet (con AcceptChanges) o deshacerlos (con RejectChanges).

Clases ADO.NET
ADO .NET define una serie de interfaces que proporcionan la funcionalidad básica
común a las distintas fuentes de datos accesibles a través de ADO .NET. La
implementación de estos interfaces por parte de cada proveedor proporciona
acceso a un tipo concreto de fuentes de datos y puede incluir propiedades y
métodos adicionales.
Interfaz IDbConnection
Establece una sesión con una fuente de datos. Permite abrir y cerrar conexiones,
así como comenzar transacciones (que se finalizan con los métodos Commit y
Rollback de IDbTransaction. Las clases SqlDbConnection y
OleDbConnection implementan el interfaz de IDbConnection.
Interfaz IDbCommand
Representa una sentencia que se envía a una fuente de datos (usualmente en SQL,
aunque no necesariemente). Las clases SqlDbCommand y OleDbCommand
implementan el interfaz de IDbCommand.
IDbCommand nos permite definir la sentencia que se ha de ejecutar, ejecutar la
sentencia, pasarle parámetros y prepararla (crear una versión "compilada" de la
misma para que su ejecución sea más eficiente cuando ha de repetirse varias
veces). El método ExecuteReader devuelve un conjunto de tuplas (véase el
interfaz IDataReader), mientras que ExecuteScalar devuelve un valor único
(p.ej. ejecución de procedimientos almacenados) y ExecuteNonQuery no devuelve
nada (p.ej. borrados y actualizaciones).

string connectionString = "Persist Security


Info=False;" +
"User ID=sa;Initial
Catalog=MYDB;" +
"Data Source=MYSERVER";

SqlConnection connection = new


SqlConnection(connectionString);

// Ejecución de sentencias SQL


// ---------------------------

string sqlInsert = "INSERT INTO


Department(DepartmentName) VALUES
(@DepartmentName)";

SqlCommand insertCommand = new


SqlCommand(sqlInsert, connection);

SqlParameter param = insertCommand.Parameters.Add


(
new
SqlParameter("@DepartmentName", SqlDbType.VarChar,
100));

param.Value = ...

connection.Open();

insertCommand.ExecuteNonQuery();

connection.Close();

// Llamadas a procedimientos almacenados


// -------------------------------------

// C#

string spName = "CREATE_DEPARTMENT"

SqlCommand command = new SqlCommand(spName,


connection);

command.CommandType = CommandType.StoredProcedure;

SqlParameter in = command.Parameters.Add (
new
SqlParameter("@DepartmentName", SqlDbType.VarChar,
100));
in.Value = ...

SqlParameter out = command.Parameters.Add (


new SqlParameter("RETVAL",
SqlDbType.Int));
out.Direction = ParameterDirection.ReturnValue;

connection.Open();

insertCommand.ExecuteNonQuery();

int newID = command.Parameters("RETVAL").Value;

connection.Close();

// SQL Server
// ----------

CREATE TABLE [dbo].[Department] (


[DepartmentID] [int] IDENTITY (1, 1) NOT
NULL ,
[DepartmentName] [varchar] (100),
[CreationDate] [datetime] NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Department] WITH NOCHECK ADD


CONSTRAINT [PK_Department] PRIMARY KEY
CLUSTERED
(
[DepartmentID]
) ON [PRIMARY]
GO

CREATE PROCEDURE dbo.CreateDepartment


@DepartmentName varchar(100),
AS
INSERT INTO Department (DepartmentName,
CreationDate)
VALUES (@DepartmentName, GetDate())
RETURN scope_identity()
GO

Interfaz IDataReader
Proporciona acceso secuencial de sólo lectura a una fuente de datos. Las clases
SqlDataReader y OleDbDataReader implementan el interfaz de IDataReader.
Al utilizar un objeto IDataReader, las operaciones sobre la conexión
IDbConnection quedan deshabilitadas hasta que se cierre el objeto
IDataReader.

string connectionString = "Provider=SQLOLEDB.1;" +


"User ID=sa;Initial
Catalog=Northwind;" +
"Data Source=MYSERVER";

OleDbConnection connection = new


OleDbConnection(connectionString);
string sqlQuery = "SELECT CompanyName FROM
Customers";

OleDbCommand myCommand = new OleDbCommand(sqlQuery,


connection);

connection.Open();

OleDbDataReader myReader =
myCommand.ExecuteReader();

while (myReader.Read()) {
Console.WriteLine(myReader.GetString(0));
}

myReader.Close();

connection.Close();

Clase DataSet
Un objeto DataSet encapsula un conjunto de tablas independientemente de su
procedencia y mantiene las relaciones existentes entre las tablas. El contenido de
un DataSet puede serializarse en formato XML. Además, se permite la
modificación dinámica de los datos y metadatos del conjunto de datos representado
por el objeto DataSet.
El interfaz IDataAdapter implementado OleDbDataAdapter y SqlDataAdapter
se utiliza para construir el conjunto de datos y actualizarlo cuando sea necesario.
Los conjuntos de datos con los que se trabaja de esta forma utilizan un enfoque
asíncrono en el que no se mantiene abierta la conexión con la base de datos a la
que se está accediendo. Al trabajar con conjuntos de datos de esta forma, se
dispone de un superconjunto de los comandos que se permiten cuando se emplea
el interfaz IDataReader. De hecho se pueden realizar operaciones de consulta
(select), inserción (insert), actualización (update) y borrado (delete).

string connectionString = "Persist Security


Info=False;" +
"User ID=sa;Initial
Catalog=Northwind;" +
"Data Source=MYSERVER";

SqlConnection connection = new


SqlConnection(connectionString);

SqlDataAdapter myDataAdapter = new


SqlDataAdapter();

DataSet myDataSet = new DataSet();

string sqlQuery = "SELECT * FROM Customers";

myDataAdapter.SelectCommand = new
SqlCommand(sqlQuery, connection);

connection.Open();
myDataAdapter.Fill(myDataSet);

conn.Close();

Clase DataTable
Representa una tabla en memoria (Columns & Rows) cuyo esquema viene definido
por su colección de columnas Columns. La integridad de los datos se conserva
gracias a objetos que representan restricciones (Constraint) y dispone de
eventos públicos que se producen al realizar operaciones sobre la tabla (p.ej.
modificación o eliminación de filas).
Clase DataColumn
Define el tipo de una columna de una tabla (vía su propiedad DataType) e incluye
las restricciones (Constraints) y las relaciones (Relations) que afectan a la
columna. Además, posee propiedades útiles como AllowNull, Unique o
ReadOnly.
Clase DataRow
Representa los datos de una tabla (almacenados en la colección Rows de un objeto
DataTable), de acuerdo con el esquema definido por las columnas de la tabla
(Columns). Además, incluye propiedades para determinar el estado de una
fila/tupla particular (p.ej. nuevo, cambiado, borrado, etc.).
Clase DataRelation
Relaciona dos DataTables vía DataColumns y sirve para mantener restricciones
de integridad referencial. Obviamente, el tipo de las columnas relacionadas ha de
ser idéntico. Para acceder a los datos relacionados con un registro concreto basta
con emplear el método GetChildRecords de la tupla correspondiente (DataRow).

Creación de una base de datos

// Creación de las tablas, columnas y claves


primarias/externas

DataTable authors = new DataTable("Author");


DataTable books = new DataTable("Book");
DataColumn id = authors.Columns.Add("ID",
typeof(Int32));
DataColumn name = new
authors.Columns.Add("Name",typeof(String));
authors.PrimaryKey = new DataColumn[] {id};
id.AutoIncrement = true;

DataColumn isbn = books.Columns.Add("ISBN",


typeof(String));
DataColumn title = books.Columns.Add("Title",
typeof(String));
DataColumn authid =
books.Columns.Add(“AuthID”,typeof(Int32));
books.PrimaryKey = new DataColumn[] {isbn};

DataColumn[] foreignkey = new DataColumn[]


{authid};
DataRelation bookauth = new
DataRelation("BookAuthors",
authors.PrimaryKey,
foreignkey);

// Creación del DataSet: tablas y relaciones

DataSet dataset = new DataSet();


dataset.DataSetName = "BookAuthors";
dataset.Tables.Add (authors);
dataset.Tables.Add (books);

dataset.Relations.Add (bookauth);

// Inserción de datos

DataRow shkspr = authors.NewRow();


shkspr["Name"] = "William Shakespeare";
authors.Rows.Add(shkspr);

DataRow row = books.NewRow();


row["AuthID"] = shkspr["ID"];
row["ISBN"] = "1000-XYZ";
row["Title"] = "MacBeth";
books.Rows.Add(row);

// Commit

dataset.AcceptChanges();

Transacciones en ADO.NET
Las transacciones son conjuntos de operaciones que han de efectuarse de forma
atómica. La acidez de una transacción hace referencia a sus propiedades deseables:
atomicidad, consistencia, aislamiento y durabilidad (ACID = Atomicity, Consistency,
Isolation, Durability).
En ADO.NET, los límites de las transacciones se indican manualmente. Los objetos
de la clase Connection tienen un método BeginTransaction que devuelve una
transacción (objeto de tipo Transaction). La transacción finaliza cuando se llama
al método Commit o Rollback del objeto Transaction devuelto por
BeginTransaction.
Data Binding
Éste es el nombre por el que se conoce el mecanismo que nos permite asociar el
contenido de un conjunto de datos a los controles de la interfaz de nuestra
aplicación, algo que facilitan los entornos de programación visual (como es el caso
del Visual Studio .NET).

Data Binding en Visual Studio .NET


Se puede optar por asistentes del tipo de DataForm
wizard... o, cuando éstos no nos ofrecen la funcionalidad
suficiente para nuestras aplicaciones, podemos programarlo
nosotros mismos (algo que no es difícil y nos da bastante
más control sobre nuestra aplicación):
• Se crean los objetos ADO.NET necesarios
(Connection, DataSet, Command y DataAdapter).
• Se enlazan los controles de la interfaz con las
columnas del DataSet, lo que se consigue
añadiendo un objeto
System.Windows.Forms.Binding a la propiedad
DataBindings del control. Los objetos de tipo
Binding nos permiten enlazar una propiedad de
un control a una columna de un DataSet.
• Se implementa la forma de recorrer los registros,
haciendo uso del objeto BindingContext asociado
al formulario (cuyas propiedades Position y
Count nos permiten movernos por el conjunto de
datos).
• Se implementan las operaciones sobre la base de
datos (con los comandos asociados al
DataAdapter.

NOTA: Cuando los conjuntos de datos sean grandes, es recomendable utilizar


ADO.NET con paginación para no tener que leer todos los datos de la base de datos
(véase "ADO.NET data paging"). En situaciones como ésa, también suele ser
recomendable añadir capacidades de búsqueda a nuestras aplicaciones (véase el
método Find).
http://elvex.ugr.es/decsai/csharp/xml/xml.xml

Como devolver y tratar información de procedimientos


almacenados
Por Alvaro

10/03/2009
Enviar esta pagina a un amigo. * *

Este articulo habla sobre tres formas comunes de cómo tratar la información devuelta de un
procedimiento almacenado después de sacarla de ellos usando variables output y el comando RETURN.
Vamos a suponer que quieres obtener de un procedimiento almacenado una lista de toda la gente
con un determinado apellido y tratar con ella. El código del procedimiento almacenado quedaría
así:
CREATE PROCEDURE dbo.GetPeopleByLastName (@LastName NVARCHAR(50))

AS

SELECT ContactID,

FirstName,

LastName

FROM Person.Contact

WHERE LastName = @LastName

ORDER BY ContactID

Si ejecutas el procedimiento devolvería esto:


EXEC dbo.GetPeopleByLastName @LastName = 'Alexander'

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ContactID FirstName LastName

----------- ----------------------------------- --------------

22 J. Phillip Alexander

23 Michelle Alexander

430 Mary Alexander

19942 Morgan Alexander

(123 row(s) affected)

Si quieres escribir el código que llama a este procedimiento almacenado y procesar los resultados
aquí te paso como seria, no olvides importar el namespace SqlClient. Lo necesitaremos para todos
los ejemplos.
Imports System.Data.SqlClient

Y el código seria este:


' La cadena de conexión de la base de datos debe venir de web.config
Dim connectionString As String = "connectionString"

Using conn As New SqlConnection(connectionString)

Using cmd As New SqlCommand("dbo.GetPeopleByLastName")

cmd.CommandType = CommandType.StoredProcedure

cmd.Parameters.Add(New SqlParameter("@LastName", "Alexander"))

conn.Open()

cmd.Connection = conn

Using rdr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)

While rdr.Read()

Dim contactID As Integer = rdr.GetInt32(rdr.GetOrdinal("ContactID"))

Dim firstName As String = rdr.GetString(rdr.GetOrdinal("FirstName"))

Response.Write(firstName + " (" + contactID.ToString() + ")")

End While

rdr.Close()

End Using

End Using

End Using

Si necesitas guardar el resultado de esta consulta usando T-SQL necesitarás un sitio para
almacenarlo como una tabla temporal, y quedaría así:
DECLARE @People TABLE (

ContactID INT,

FirstName NVARCHAR(50),

LastName NVARCHAR(50)

INSERT @People (ContactID, FirstName, LastName)

EXEC dbo.GetPeopleByLastName @LastName = 'Alexander'

SELECT COUNT(*) FROM @People

GO

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(123 row(s) affected)

-----------
123

(1 row(s) affected)

Usando variables OUTPUT

Si solo quieres devolver un valor (o varios) puedes usar este modo, con lo que el procedimiento
almacenado quedaría así:
CREATE PROCEDURE dbo.GetCountByLastName (

@LastName NVARCHAR(50),

@LastNameCount INT OUTPUT )

AS

SELECT @LastNameCount = COUNT(*)

FROM Person.Contact

WHERE LastName = @LastName

Si queremos devolver el valor con T-SQL usaríamos este código:


DECLARE @TheCount INT

EXEC dbo.GetCountByLastName

@LastName = 'Alexander',

@LastNameCount = @TheCount OUTPUT

SELECT TheCount = @TheCount

GO

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

TheCount

-----------

123

(1 row(s) affected)

Para obtener la información desde código de cliente lo tenemos aquí:


' La cadena de conexión de la base de datos debe venir de web.config

Dim connectionString As String = "connectionString"

Using conn As New SqlConnection(connectionString)

Using cmd As New SqlCommand("dbo.GetCountByLastName")

cmd.CommandType = CommandType.StoredProcedure

cmd.Parameters.Add(New SqlParameter("@LastName", "Alexander"))


Dim countParameter As New SqlParameter("@LastNameCount", 0)

countParameter.Direction = ParameterDirection.Output

cmd.Parameters.Add(countParameter)

conn.Open()

cmd.Connection = conn

cmd.ExecuteNonQuery()

Dim count As Integer = Int32.Parse(cmd.Parameters("@LastNameCount").Value.ToString())

Response.Write("<p>Count: " + count.ToString())

conn.Close()

End Using

End Using

Usando el comando Return

La última manera para conseguir la información devuelta del procedimiento almacenado es


también la más limitada. Solo devuelve un valor numérico. Es más usado comúnmente para
devolver números de error o estados de como se encuentra la rutina. Mira este procedimiento
almacenado:
CREATE PROC dbo.TestReturn (@InValue int)

AS

Return @Invalue

GO

Todo lo que hace es devolver el valor que le pasamos en el parámetro de entrada. Tienes que
saber también que ejecutar el comando return hace que se pare la ejecución del procedimiento
almacenado y devuelva el control al programa que lo llamó. Por eso es mas a menudo usado para
errors y parar el proceso si un error es encontrado. El código siguiente llama al procedimiento
almacenado TestReturn:
DECLARE @ReturnValue INT

EXEC @ReturnValue = TestReturn 3

SELECT ReturnValue=@ReturnValue

Y la salida se parecería a esto:


ReturnValue

-----------

(1 row(s) affected)
Cualquier numero que vuelva de la variable RETURN es depositado en @ReturnValue . El código de
cliente para obtener el valor devuelto en RETURN es:
Dim connectionString As String = "connectionString"

Using conn As New SqlConnection(connectionString)

Using cmd As New SqlCommand("dbo.TestReturn")

cmd.CommandType = CommandType.StoredProcedure

cmd.Parameters.Add(New SqlParameter("@Invalue", 3))

Dim returnValue As New SqlParameter("@Return_Value", DbType.Int32)

returnValue.Direction = ParameterDirection.ReturnValue

cmd.Parameters.Add(returnValue)

conn.Open()

cmd.Connection = conn

cmd.ExecuteNonQuery()

Dim count As Integer = Int32.Parse(cmd.Parameters("@Return_Value").Value.ToString())

Response.Write("<p>Return Code: " + count.ToString())

conn.Close()

End Using

End Using

Estas son las mejores maneras para leer la información devuelta de un procedimiento
almacenado.

ONTENIDO
• 1.0- Introducción

• 2.0- Software Requerido

• 3.0- Configuración de Informix-Connect 3.0

• 4.0- Agregar servicio y host en Windows

• 5.0- Agregando Referencia IBM.Data.Informix en Proyecto

• 6.0- Definición de la cadena de conexión Informix

• 7.0- Guardar la cadena de conexión en un Archivo de Configuración

• 8.0- Abrir y Cerrar Informix con Objeto de Conexión Ado.Net


• 9.0- Cargar Datos y Crear Stored Procedure en Informix

• 10.0- Ejecutar Stored Procedure y Visualizar Datos en un

DataGridView

• 11.0- Conclusiones

1.0-Introducción

En las aplicaciones Windows la conexión a la base de datos Informix es crítica y


requiere de un alto nivel de seguridad. ADO.Net permite definir la conexión
mediante la propiedad " connectionstring " del objeto de conexión. Definir y
almacenar la cadena de conexión Informix, apropiadamente, es una tarea
importante que tenemos como desarrolladores. En este artículo tú verás como
iniciar y asegurar la cadena de conexión para aplicaciones Windows usando VB.Net
2005. También aprenderemos como llamar a un Procedimiento Almacenado con
parametros de entrada desde VB.Net 2005 y finalmente veremos como mostrar la
información devuelta por nuestro Procedimiento Almacenado en un DatagridView.
Como un valor agregado a este artículo también encontrarás como configurar el
Windows para que pueda trabajar con el Informix Dynamic Server.

Nota:
Este artículo esta orientado a desarrolladores Novatos(no tan novatos,
se requieren tener los conocimientos básicos de programación, haber
trabajado un poco con Ado.Net o por lo menos entender el concepto) y
a los DBA en Informix que buscan desarrollar aplicaciones en .NET pero
cuentan con muy poco tiempo para investigar.

2.0-Software Requerido

• Informix Dynamic Server(IDS) 9 o superior

• IBM Informix-Connect 3.0

• Visual Basic 2005

Nota:
Tanto él Informix Dynamic Server(IDS) como IBM Informix-Connect
3.0 pueden ser descargados(trial version) gratuitamente de la página
de IBM.(es necesario que primero te registres en él sitio (si lo sé es un
gorro tener que hacer esto....pero lo piden, ¡Ánimooo!.).

3.0-Configuración de Informix-Connect 3.0


Antes de usar el proveedor nativo Informix para .Net deberás estar seguro que
Informix-Connect 3.0 trabaja apropiadamente. Una vez instalado IBM Informix-
Connect 3.0 es recomendable modificar la variable DBDATE=dmy4/, para lograr
esto ve al menú Inicio>Todos los programas>IBM Informix Connect
3.0>SetNet32, claro que esto sólo aplica en caso de que desees trabajar las fechas
en formato DIA/MES/AÑO por ejemplo (24/07/2008).

Nota:
Cuando distribuyas tú aplicación, es necesario que la máquina cliente
tenga instalado Informix-Connect 3.0 y el Framework.NET 2.0.

4.0-Agregar servicio y host en Windows

Si el servidor IDS(Informix Dynamic Server) esta instalado en una máquina


remota es necesario que especifiques el nombre del servicio y la dirección IP del
servidor. Para establecer el servicio abre el archivo services
(C:\WINDOWS\system32\drivers\etc) escribe el nombre del servicio,puerto y el
protocolo, ejemplo:
noreste_tcp 1526/tcp
La dirección IP se estable en el archivo host (C:\WINDOWS\system32\drivers\etc)
teclea la IP del servidor y el nombre del host. Por ejemplo:
192.179.188.65 noreste
IMPORTANTE: Si el IDS no reside en un servidor remoto, al instalar el IDS puedes
tomar los valores que vienen por defecto(es decir, no es necesario que hagas lo
anterior).

5.0-Agregando Referencia IBM.Data.Informix en Proyecto


Para que puedas hacer uso del proveedor nativo de Informix, antes es necesario
que SUMES una referencia al Proyecto. En la ventana Solution Explorer,
seleccionamos el nombre del proyecto(ese que te indica la ruta), damos clic
derecho, seleccionamos Add Reference, pestaña Browse, buscamos el archivo
IBM.Data.informix.dll para .Net 2.0 (recuerda la ruta donde instalaste IBM
Informix-Connect 3.0) y seleccionamos OK.

6.0-Definición de la cadena de conexión Informix

La cadena de conexión es una propiedad del objeto de conexión ADO.Net


IfxConnection. Esta es utilizado para conectarse con el servidor de Base de Datos
Informix. La cadena de conexión contiene una serie de parámetros separados por
puntos y comas(;). Estos parámetros tienen nombres especificos, definidos en el
proveedor .NET tales como Dsn, Host, Server, Service, Protocol, Database, Uid,
Pwd etc. Si un parámetro no es especificado en la cadena de conexión se asume su
valor por defecto. El ejemplo 1 te muestra una cadena de conexión simple de
Informix.
Dim IfxCadenaConexion As String
ifxCadenaConexion = "Host=nombrehosts;" & _
"Server=myServer;" & _
"Service=ServiceName;" & _
"Protocol=olsoctcp;Database=myDataBase;" & _
"Uid=UserName;Pwd=myPassword;"
Ejemplo 1: Cadena de Conexión Informix

Después de que la cadena de conexión ha sido definida apropiadamente, esta


puede ser usada por el objeto de conexión IfxConnection como un constructor o
como una propiedad. Dentro del Ejemplo 2 la cadena de conexion
IfxCadenaConexion es usada como un constructor. El método Open() del objeto de
conexión establece una nueva conexión.
Dim ifxCadenaConexion As String
Dim IfxADOConexion As IfxConnection
ifxCadenaConexion = "Host=HostName;" & _
"Server=MyServerName;" & _
"Service=MyServiceName;" & _
"Protocol=olsoctcp;Database=MyDataBase;" & _
"Uid=myUserName;Pwd=MyPassword;"

IfxADOConexion = New IfxConnection(ifxCadenaConexion)


IfxADOConexion.Open()
Ejemplo 2: Cadena de Conexión pasado como constructor al Objeto de Conexión ADO.Net

Dentro del Ejemplo 3 se indica como la cadena de conexión es usada como una
propiedad del objeto de conexión IfxConnection.
Dim ifxCadenaConexion As String
Dim IfxADOConexion As IfxConnection
ifxCadenaConexion = "Host=hostname;" & _
"Server=myServerAddress;" & _
"Service=service-name;" & _
"Protocol=olsoctcp;Database=myDataBase;" & _
"Uid=myUsername;Pwd=myPassword;"
IfxADOConexion = New IfxConnection()
IfxADOConexion.ConnectionString = ifxCadenaConexion
IfxADOConexion.Open()
Ejemplo 3: Cadena de Conexión usada como propiedad del Objeto de Conexión ADO.Net

7.0-Guardar la cadena de conexión en un Archivo de


Configuración

Una conveniente práctica de programación, es almacenar la cadena de conexión en


un Archivo de Configuración. Esto permite un fácil mantenimiento de la aplicación
en futuras actualizaciones, en caso de que que los párametros de la cadena de
conexión requieran ser cambiados. Así que, como buenos desarrolladores que
somos nunca colocamos la cadena de conexión embebida en nuestro código(Ver
Ejemplo 1). Para comodidad de nosotros Visual Studio.Net 2005 hace sencilla la
tarea de almacenar las configuraciones de nuestra aplicación dentro de un archivo
de configuración(app.config). Para lograr esto, da un clic derecho en tu proyecto
(ventana Solution Explorer) y selecciona Properties. Luego selecciona la pestaña
Settings y teclea la información de abajo especificando los valores requeridos
según corresponda(Figura 1).

Scop
Name Type Value
e
IfxCadenaConexio (ConnectionString Applicatio Database=yyy;Uid=yyy;
n ) n Pwd=yyy;
Server=yyy;Service=yyy
;

Figura 1: Configuraciones de nuestra Aplicación.

En las aplicaciones Windows, dentro del archivo de configuración App.Config existe


la sección < ConnectionString > la cual almacena el valor de la cadena de
conexión, como la mostrada en el ejemplo 4.
<connectionStrings>
<add
name="WindowsApplication1.My.MySettings.IfxCadenaConexion"
connectionString="Server=yyy;Database=yyy;Uid=yyy;
pwd=yyy; service=yyy" />
</connectionStrings>
Ejemplo 4: Sección ConnectionString del archivo App.Config.

En VB.Net 2005 el valor de la cadena de conexión puede ser rescatado usando el


objeto " My " como se muestra en el ejemplo 5.
Dim mIfxCadenaConexion As String = My.Settings.IfxCadenaConexion
Ejemplo 5: Rescatando el valor de la cadena de conexión.

El beneficio de hacer uso del archivo app.config, es por la razón de que sí los
parámetros de la cadena de conexión cambian, la actualización será sencilla.
Compilar la aplicación nuevamente no será necesario. Detalles en el ejemplo 6.
Dim mifxCadenaConexion As String = My.Settings.IfxCadenaConexion
Dim IfxADOConexion As New IfxConnection
IfxADOConexion.ConnectionString = mifxCadenaConexion
IfxADOConexion.Open()
Ejemplo 6: Abrir conexión Informix de la cadena de conexión almacenada.

8.0-Abrir y Cerrar Informix con Objeto de Conexión Ado.Net

Para que podamos abrir nuestra conexión podemos hacer lo siguiente:


1-Crear una instancia del objeto de conexión IfxConnection.
2-Pasar la cadena de conexión como constructor ó bien especificar el valor de la
propiedad ConnectionString.
3-Usar el método Open().(Ver Ejemplo 7)
Para cerrar la conexión haremos uso de la función IsNothing()para chequear el
estado de la conexión.(Ver Ejemplo 8). OJO Mágico " Es recomendable tomar en
cuenta que una conexión a la base de datos debe ser abierta lo más tarde posible
y cerrada lo antes posible. "
Private mIfxCadenaConexion As String = My.Settings.IfxCadenaConexion
Private mIfxConexion As IfxConnection

Private Function IfxADOAbrirConexion(ByRef str_MensajeError As String)


As Boolean
Try
mIfxConexion = New IfxConnection
mIfxConexion.ConnectionString = mIfxCadenaConexion
mIfxConexion.Open()
Return (True)
Catch ex As Exception
str_MensajeError = ex.Message
Return (False)
End Try
End Function
Ejemplo 7: Método para Abrir la Conexión a Informix.
Private Function IfxADOCerrarConexion(ByRef str_MensajeError As
String) As Boolean
Try
If Not IsNothing(mIfxConexion) Then
If mIfxConexion.State = ConnectionState.Open Then
mIfxConexion.Close()
End If
mIfxConexion = Nothing
End If
Return (True)
Catch ex As IfxException
str_MensajeError = ex.Message
Return (False)
End Try
End Function
Ejemplo 8: Método para Cerrar la Conexión a Informix.

9.0-Cargar Datos y Crear Stored Procedure en Informix

Un Procedimiento Almacenado es un programa escrito en lenguaje del DBMS, los


cuales son almacenados como parte de la Base de Datos. La experiencia nos ha
enseñenado ha hacer uso de las herramientas que otros desarrolladores ya han
invertido tiempo en construir, pero con la intención de favorecer a los escasos de
tiempo (yo sé que los desarrollares somos muy jaladores pero lo que hace grande
nuestro trabajo es debido a que trabajamos en equipo, así que hagamos uso de lo
que ya esta funcionando; para que quemar neuronas si ya esta hecho, ¡Digoo
No!), una de ellas son los SP los cuales tienen las siguientes ventajas:
a)Reuso de Código: Aplicaciones que usan la misma Base de Datos, pueden
compartir los procedimientos almacenados, evitando el doble código
b)Fácil Actualización: Si un procedimiento es cambiado, las modificaciones se
reflejan automáticamente en la aplicación.
c)Respuesta: Debido a que los procedimientos son ejecutados en el servidor, esto
reduce el tráfico en tú red.
Informix proporciona un programa llamado DBACCESS, el cual vamos a utilizar
para crear nuestro procedimiento almacenado y una sencilla tabla. Para hacer esto
dentro de la interfaz del DBACCESS vamos a la opción Query-Language y
tecleamos el código mostrado en el Ejemplo 9 y 10.
Create table claves_proveedor(no_proveedor integer,clave nchar(10),
descripcion nchar(35), email nchar(40));

Insert into claves_proveedor(no_proveedor,clave,descripcion,email)


Values (1,’0003’,’novartis’,’pedro@novartis.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (1,’1415’,’ novartis’,’carlos@novartis.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (1,’2424’,’ novartis’,’tania@novartis.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (2,’6454’,’infomed’,’alonso@infomed.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (2,’3624’,’infomed’,’medina@infomed.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (2,’1456’,’infomed’,’paco@infomed.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (3,’2111’,’carmenMed’,’castro@carmenMed.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (4,’0345’,’fibrotests’,’olga@fibrotests.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (5,’5798’,’maypo’,’maria@maypo.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (6,’8974’,’infinity’,’rosy@infinity.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (7,’6531’,’camilamed’,’lulu@camilamed.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (8,’9862’,’femara’,’fernando@femara.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (9,’0002’,’farmacias’,’agosto@farmacias.com.mx’);
Insert into claves_proveedor(no_proveedor,clave,descripcion,email)
Values (10,’0078’,’pisa’,’regina@pisa.com.mx’);
Ejemplo 9: Definiendo la tabla claves_proveedor e insertando datos.
Create Procedure sp_Select_Proveedor(no_prov integer)Returning int,
nchar(10),nchar(10),nchar40;
Define _no_proveedor int;
Define _clave nchar(10);
Define _descripcion nchar(10);
Define _email nchar(40);
Foreach
Select no_proveedor, clave, Descripcion, email
Into _no_proveedor,_clave,_descripcion,_email
from claves_proveedor where no_proveedor=no_prov;
Return _no_proveedor,_clave,_descripcion,_email with resume;
End Foreach;
End Procedure;
Ejemplo 10: Procedimiento Almacenado para seleccionar los registros de la tabla claves_proveedor por el número de proveedor.

10.0-Ejecutar Stored Procedure y Visualizar Datos en un


DataGridView
Para demostrar que todo lo que se dice arriba es verdad y funciona, se ha creado
una solución sencilla con un formulario como el mostrado en la Figura 1. Este
formulario carga la información según el número de proveedor.

Figura 2: Formulario Conectar Informix con Stored Procedure.


El código del evento click del botón Buscar es mostrado en el Ejemplo 11. El código
crea una nueva instancia de la clase InformixCadenaConexion y pasa la cadena de
conexión mIfxCadenaConexion como un constructor. Finalmente retorna el
mensaje de error(si lo hubiera) mediante el parametro str_MensajeError. Si un
error ocurre un mensaje sera mostrado al usuario final. La instancia
CadenaConexionObjeto llama al método DataGridViewLoadData (ejemplo 12). Este
código utiliza el bloque Try..Catch block. En el bloque Try, el objeto de conexión
ADO.net es abierto. Una nueva instancia del objecto ifxCommand es creada para
asignar el procedimiento almacenado sp_Select_Proveedor a la propiedad
CommandText. Después nosotros creamos una nueva instancia del objeto
dataapdater IfxDataAdapter para almacenar la información devuelta por el
procedimiento almacenado.
Private mIfxCadenaConexion As String = My.Settings.IfxCadenaConexion
Private str_MensajeError As String

Private Sub btnBuscar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnBuscar.Click
Using CadenaConexionObjeto As New
InformixCadenaConexion(mIfxCadenaConexion)
Dim tabla As New DataTable
tabla =
CadenaConexionObjeto.DataGridViewLoadData(DataGridView1,
str_MensajeError, CInt(TextBox1.Text))
If Not IsNothing(str_MensajeError) Then
MessageBox.Show(str_MensajeError, _
Me.Text, _
MessageBoxButtons.OK, _
MessageBoxIcon.Information)
End If
DataGridView1.DataSource = tabla
End Using
End Sub
Ejemplo 11: Evento click del botón Buscar.
Public Function DataGridViewLoadData(ByVal DataGrid As DataGridView,
ByRef str_MensajeError As String, ByVal parm_NoProveedor As Integer)
As DataTable
Dim tabla As New DataTable

Try
Using mifxConexion As New
IfxConnection(mIfxCadenaConexion)
mifxConexion.Open()
Using mIfxComando As New IfxCommand
With mIfxComando
.Connection = mifxConexion
.CommandText = "sp_Select_Proveedor"
.CommandType = CommandType.StoredProcedure
.Parameters.Add(New
IfxParameter("no_prov", IBM.Data.Informix.IfxType.Integer))
.Parameters("no_prov").Value =
parm_NoProveedor
End With
Using mIfxAdaptador As New IfxDataAdapter
mIfxAdaptador.SelectCommand = mIfxComando
mIfxAdaptador.Fill(tabla)
End Using
End Using
End Using
Catch ex As IfxException
str_MensajeError = ex.Message
End Try
Return Tabla
End Function
Ejemplo 12: Método DataGridViewLoadData.

Finalmente nosotros obtendremos la información del proveedor, como vemos en la


figura 3.

Figura 3: Formulario Conectar Informix con Stored Procedure(Resultados).

11.0-Conclusiones
Al establecer la conexión con Informix desde VB.Net 2005, requiere que tomes la
precaución de almacenar la cadena de conexión en el archivo de configuración de
la aplicación. No olvides que si estas trabajando con Bases de Datos,
categóricamente te recomiendo que uses procedimientos almacenados. Los
detalles de este articulo los encuentras en el código fuente, puedes descargarlo en
el link que viene abajo. Espero que esta información te sea de gran utilidad.
¡¡¡Mucho éxito!!!. Atte: Cascor.
"Trabajo, Ciencia y Verdad".

Espacios de nombres usados en el código de este artículo:


IBM.Data.Informix

You might also like