módulo_8_acceso a bases de datos con ado

133
CARACTERÍSTICAS GENERALES DE ADO.NET © élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Upload: pablo-alvarez

Post on 24-Jul-2015

145 views

Category:

Documents


1 download

DESCRIPTION

Características generales de ADO.NET, Proveedores de datos, Fundamentos del lenguaje SQL, EL gestor de bases de datos SQL Server, Acceso a datos en modo conectado, Vinculación de controles Windows a datos, ADO.NET ejemplos de acceso a bases de datos, Prácticas.

TRANSCRIPT

Page 1: Módulo_8_Acceso a bases de datos con ADO

CARACTERÍSTICASGENERALES DE

ADO.NET

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 2: Módulo_8_Acceso a bases de datos con ADO

Características

ADO.NET es la tecnología utilizada en el entorno .NET Framework para accesoa datos.

Está constituida por toda una colección de clases especializadas que nosfacilitan enormemente la vida a la hora de codificar acceso a datos.

Lógicamente, está totalmente integrado en el IDE de Visual Studio, con locual, mediante sus asistentes, será aún más fácil la creación eimplementación de los accesos a datos, al haber sido contemplado comoorigen de datos de todos los controles susceptibles de tener origen de datos(DataBindings).

Permite el acceso a casi cualquier fuente de datos, como por ejemplo:

Clases de ADO.NET

Las clases de ADO.NET están fuertemente orientadas al acceso compartido a orígenes de datos remotos,contemplando todo tipo de situaciones posibles en sus propiedades, métodos y eventos, con lo que sólo sehan de implementar las reacciones de los programas a los acontecimientos, sin tener que codificar el controlde los mismos, ya que viene integrado.

CARACTERÍSTICAS GENERALES DE ADO.NET

2

Page 3: Módulo_8_Acceso a bases de datos con ADO

Está preparado para el acceso conectado y desconectado a las fuentes de datos, siendo el método conectadoel tradicional acceso que abre la comunicación con la base de datos y la mantiene abierta hasta que finalizala actualización de datos y el método desconectado el que se trae los datos requeridos, desconecta de la basede datos y cuando es necesario actualizar los mismos en el origen de datos, vuelve a conectar con la basede datos.

Ventajas de ADO.NET

Una de las ventajas de ADO.NET es que el acceso a datos es coherente, sea cual sea el origen de los mismos,lo que permite, dentro de las capas de abstracción:

1. Acceder a los datos de un determinado origen o tecnología en un módulo especializado.

2. Pasar a cualquier otro tipo de origen codificando otro módulo que mantenga el mismo interfaz,siendo este cambio transparente para el codificador del módulo que consuma los datos.

DataSets

En los programas se utilizará principalmente DataSets.

Son un conjunto de datos desconectados de su origen y con la posibilidad decombinar información de distintas tablas, incluso de distintos orígenes dedatos.

Esto separa lo que es el acceso a los datos, propiamente dicho, de lapresentación y manipulación que se pueda realizar en el código, facilitandoel control e implementación.

También se pueden utilizar los DataSets para cualquier tipo de datos, incluso propios, generados enel proceso o recuperados de archivos de texto, XML local… con lo que la integración es total, dandoa cualquier tipo de dato el mismo tratamiento e interfaz en los programas.

CARACTERÍSTICAS GENERALES DE ADO.NET

3

Page 4: Módulo_8_Acceso a bases de datos con ADO

Entity Framework

Para poder trabajar de una forma totalmente autónoma, ADO.NET nossuministra Entity Framework, que permite generar nuestro propio modelo dedatos, para poder trabajar con nuestra propia estructura, que no es necesarioque tenga relación específica con el cómo esté organizada la información enel origen de datos.

Para poder trabajar cuentas con:

Entity Data Model

Para la generación de los esquemas XML que definen los Entity Data Model o EDM asociados a esta tecnología,disponemos del Lenguaje CSDL que permite:

- Definir las propias clases de datos.

- Asociarlas a la implementación real en los diversos orígenes de datos asociados a los mismos.

El acceso a estos modelos de entidad se realizará mediante unas clases del CLR u otras propias quedesarrollemos nosotros mismos, mediante los servicios de objetos. Éstos también sirven para obtenercompatibilidad con la infraestructura del Entity Framework, administración de los estados, seguimiento decambios…

CARACTERÍSTICAS GENERALES DE ADO.NET

4

Page 5: Módulo_8_Acceso a bases de datos con ADO

Language Integrated Query

Ya hemos visto que existe un nuevo lenguaje de acceso a datos, el Language Integrated Query, o LINQ, el cualsirve…

Entity SQL

En el modo tradicional de codificación, también se dispone de Entity SQL, el cual, como su nombre indica,permite el acceso al modelo de datos mediante instrucciones clásicas de SQL.

Para introducir las consultas de datos directamente en un código, siempre ycuando sea uno de los lenguajes soportados por el .NET Framework. Una desus implementaciones es el LINQ To Entities, englobado en el EntityFramework, para el acceso mediante este lenguaje a los objetos del modelode entidades.

Entity Client

Relacionado con el anterior están:

Entity Client

El cual suministra las conexiones y comandos requeridos para trabajar desde SQL con el modelo de entidades.

Servicios de datos ADO.NET

Especializados en el suministro de servicios de datos, contra EntityFramework, hacia la red.

Las distintas versiones de ADO.NET, asociadas a las distintas versiones de.NET Framework son, inicialmente, compatibles entre sí. Excepto, porsupuesto, las nuevas funcionalidades incorporadas en las versionesposteriores.

Se pueden tener distintas versiones de .NET Framework instaladas en una máquina y cada aplicación correrácon la versión para la que fue compilada o la más cercana y compatible de la que encuentre en el sistema.

Con ADO.NET pasa exactamente lo mismo, aunque, por supuesto, es recomendable compilar una versión delos programas para cada versión de .NET Framework y correr en cada máquina la versión correspondiente ala más reciente de las instaladas, más que nada, para estar seguro de disponer, en ejecución, detodas las funcionalidades que se hayan utilizado en el código.

CARACTERÍSTICAS GENERALES DE ADO.NET

5

Page 6: Módulo_8_Acceso a bases de datos con ADO

Resumen

Has llegado al final de esta lección de formación que denominamos “Características Generales de ADO.NET”.En esta lección hemos estudiado los siguientes contenidos:

CARACTERÍSTICAS GENERALES DE ADO.NET

6

Page 7: Módulo_8_Acceso a bases de datos con ADO

PROVEEDORES DEDATOS

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 8: Módulo_8_Acceso a bases de datos con ADO

Características

Un proveedor de datos, en ADO.NET es cualquiera de los conjuntos de clases especializadas en el acceso alos datos de un determinado tipo de origen de datos.

Al recuperar la información, ADO.NET la coloca en un DataSet o conjunto de datos.

Esto permite trabajar cómodamente, sin necesidad de tener la conexión abierta y, al finalizar la presentacióny manipulación de datos, abrirá automáticamente la conexión, otra vez, para efectuar las actualizacionescorrespondientes, comprobando antes que la situación de los datos originales no haya cambiado, avisandoen caso contrario.

Proveedores

Hay básicamente dos tipos de proveedores:

DataReaders

Los que son para sólo lectura adelante y están altamente optimizadospara ello.

DataAdapters

Los que permiten todo tipo de acceso a los datos, y normalmentedevuelven un DataSet.

PROVEEDORES DE DATOS

2

Page 9: Módulo_8_Acceso a bases de datos con ADO

Objetos específicos de proveedores

Dentro de lo que se denomina proveedor de datos de ADO.NET tenemos varios objetos específicos.

La mayoría de estas clases son las genéricas, es decir, luego trabajarás realmente con la versión especializadadel proveedor de datos que necesites. Por ejemplo: SQLConnection, SQLCommand,…

ConnectionQue conecta con el origen de datos concreto.

CommandQue suministra la interfaz con los comandos específicos del origen de datos. Que conecta con el origen dedatos concreto.

DataReaderDa un acceso optimizado para la lectura de datos.

DataAdapterSuministra el DataSet y lo comunica con el origen de datos, mediante objetos Command en ambos sentidos.

DataSetConjunto de datos que permite la alimentación del conjunto de datos en una operación y trabajar con ellosde forma desconectada, dejando la conexión libre para otro usuario y no bloqueando el origen de datos. LosDataSets contienen objetos de tipo DataTable, con los datos y su información relacional correspondiente.

Esquema explicativo de proveedor de datos

Para ilustrar mejor lo visto hasta ahora revisaremos un pequeño esquema que servirá de ayuda para mostrarla relación entre un proveedor de datos, el origen de datos, un DataAdapter y un DataSet.

PROVEEDORES DE DATOS

3

Page 10: Módulo_8_Acceso a bases de datos con ADO

Tipos de acceso a datos

Es importante que antes de empezar a codificar tengamos en cuenta el tipo de acceso a datos quenecesitaremos.

1. Leer datos para presentarlos al usuario para que los consulte, sin modificar nada

La opción será del DataReader. Aunque esté limitado al acceso de sólo lectura adelante, se puede rellenarun DataSet con un DataReader, la funcionalidad de paginación atrás, caso de ser necesaria, se puedeimplementar en el código o utilizando un control que la tenga directamente implementada.

2. Actualizar datos, combinar información de varios orígenes, realizar mucho trabajocon los datos antes de poder devolverlos al origen de datos, acceder de forma remotao contra XML.

Habrá de utilizarse un DataAdapter.

Un detalle importante, el DataAdapter utiliza un DataReader para recuperar los datos y cargar el DataSet,pero si sólo se va a efectuar lectura de datos, siempre tendrá mejor rendimiento si se utiliza directamenteel Datareader, al no necesitar ocupar la memoria ni el procesador con los objetos del DataAdapter y DataSety su correspondiente gestión y posterior eliminación.

Listado de Proveedores

A continuación mostramos una pequeña lista con los diferentes proveedoresde datos que ya vienen con .Net Framework, lo cual no excluye que ennuestra organización hayan adquirido alguno de un fabricante externo quesea el que se haya de utilizar. Pero si está integrado con .NET Framework,todo lo que aquí expliquemos será totalmente aplicable a dicho proveedor.

PROVEEDORES DE DATOS

4

Page 11: Módulo_8_Acceso a bases de datos con ADO

De qué están compuestos los Proveedores

Una vez vistas las denominaciones de los proveedores de datos de ADO.NET, vamos a ver de qué estáncompuestos.

Los cuatro remarcados son los principales objetos de los proveedores de datos, tal y como había quedado yareflejado en el diagrama.

Como es lógico, los proveedores de datos específicos para un determinado tipo de origen de datos tendránsiempre mejor rendimiento que aquellos que permitan acceder a los mismos mediante una o más capasintermedias además de estar altamente especializados en dicho origen de datos y sus procedimientos ymétodos.

En cambio los inespecíficos, como son OleDb y Odbc, han de realizar una transformación de los comandos yórdenes pasadas al formato concreto del origen de datos al que se conectan, así como transformar los datosya que algunos formatos son incompatibles.

Se facilita el acceso a SQL y Oracle desde los proveedores OleDb y Odbc para poder acceder a las versionesanteriores a las soportadas por los proveedores de datos específicos de dichos orígenes, aunque es posibleacceder también a las versiones más modernas, pero como se ha explicado anteriormente sería unapérdida de recursos.

PROVEEDORES DE DATOS

5

Page 12: Módulo_8_Acceso a bases de datos con ADO

Resumen

Has llegado al final de esta lección de formación que denominamos “Proveedores de Datos”.En esta lección hemos estudiado los siguientes contenidos:

PROVEEDORES DE DATOS

6

Page 13: Módulo_8_Acceso a bases de datos con ADO

FUNDAMENTOS DELLENGUAJE SQL

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 14: Módulo_8_Acceso a bases de datos con ADO

ÍNDICE

FUNDAMENTOS DEL LENGUAJE SQL

1. Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3

2. Lenguaje de definición de datos (LDD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5

3. Lenguaje de manipulación de datos (LMD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7

4. Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9

5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13

Page 15: Módulo_8_Acceso a bases de datos con ADO

1.Características

Definición del lenguaje SQL

El lenguaje SQL sirve para la definición, gestión y el acceso a los datos de labase de datos, es decir, se utiliza el mismo lenguaje, aunque nonecesariamente las mismas instrucciones para todo el ciclo de vida de losdatos, lo cual ya es una ventaja al no tener que conocer varios lenguajespara las distintas funcionalidades.

LENGUAJE DE CONSULTA ESTRUCTURADO

Historia

El Lenguaje SQL fue creado, inicialmente, por IBM, aunque fue Oracle quiénlo lanzó por primera vez al uso público.

A lo largo del tiempo ha ido sufriendo diversas modificaciones y versiones,siendo la última, de momento, la versión estándar del año 2006 (al menossegún el instituto Americano de Normalización o ANSI).

Uno de los problemas es que cada fabricante decide cuál de las versionesoficiales es la que le interesa soportar y después le aporta ese “sabor”especial que lo hace diferenciarse de la competencia y pone las cosas tandifíciles a los desarrolladores.

FUNDAMENTOS DEL LENGUAJE SQL

3

Page 16: Módulo_8_Acceso a bases de datos con ADO

Sistemas Gestores de Bases de Datos Relacionales

La inmensa mayoría de sistemas gestores de bases de datos relacionales,también conocidos por sus siglas SGBDR, soportan en su totalidad la versióndel ANSI SQL del 92, llegando también muchos de ellos al soporte de laversión del 99. Pero el soporte de las versiones posteriores, que son las queincluyen el soporte a XML, sólo lo están dando los muy grandes: Oracle, IBM,Microsoft, que son los interesados en que se implante este tipo de estándarde intercambio de datos. El resto no ha desarrollado todavía, a fecha de hoy,este soporte.

Está soportado por una fuerte base matemática, siendo de alto nivel y declarativo.

Declarativo: que dice lo que quiere hacer, pero no cómo se ha de hacer ni en qué orden. Será el SGBDR elque traduzca lo que le dices a lo que tiene que hacer de una forma optimizada, ya que si manipulamosnosotros estas cosas, lo más seguro es que lo estropeemos.

Alto nivel: en una instrucción (sentencia) se unen muchas órdenes, que en otros lenguajes de bajo nivel sedeberían dar una por una.

Modelos de datos relacional

Las características de los modelos de datos relacionales son:

- Los datos se almacenan en tablas (filas + columnas)

- Cada fila corresponde a un registro (tupla).

- Cada columna corresponde a un campo.

- Cada columna tiene un tipo de dato.

- Los tipos de datos son limitados (números y cadenas, básicamente).

- Un campo de un registro, sólo puede contener un dato.

- Las relaciones no son explícitas (se hacen mediante correspondencia de campos).

- Las relaciones muchos a muchos requieren de tablas intermedias (que contienen lasrelaciones).

FUNDAMENTOS DEL LENGUAJE SQL

4

Page 17: Módulo_8_Acceso a bases de datos con ADO

2. Lenguaje de definición de datos (LDD)

Dentro del lenguaje SQL, siendo un único lenguaje, hay una subdivisión interna entre las instruccionesatendiendo a su funcionalidad:

El lenguaje de definición de datos es el que permite al administrador de la base de datos, gestionar laestructura de la base de datos. Es decir, crear, modificar o eliminar tablas, índices, triggers...

Operaciones básicas

Las operaciones básicas que se pueden realizar en el Lenguaje SQL son:

CreateComo su nombre indica, permite la creación de cualquiera de los tipos de objetos antes mencionados, queexplicaremos, en detalle, más adelante.

AlterEs para efectuar alteraciones, es decir modificaciones, en la estructura de algún objeto de la base de datos,no en los datos.

DropElimina totalmente un determinado objeto de la base de datos.

TruncateVacía de contenido un objeto de la base de datos. Hay casos en que es más rápido que Delete (que se veráen la parte de lenguaje de manipulación de datos) ya que realmente efectúa un Drop y Create consecutivos,en lugar de la eliminación individual del contenido del objeto.

FUNDAMENTOS DEL LENGUAJE SQL

5

Page 18: Módulo_8_Acceso a bases de datos con ADO

Tipos de objeto

Los diferentes tipos de objetos del Lenguaje SQL son:

DatabaseLa base de datos completa, en algún momento se ha de crear, modificar o eliminar.

TableUna tabla física de datos, que es como se denomina al conjunto de registros que contienen la mismainformación.

ViewUna tabla lógica de datos contenidos en unas tablas físicas.

IndexUn índice, asociado normalmente a una tabla, para facilitar el acceso por un determinado campo de lamisma.

TriggerSon conjuntos de instrucciones almacenados en la base de datos, que se asocian a alguno de los tipos deoperación que se pueden efectuar en el lenguaje de manipulación de datos que luego veremos y que, cuandose produce esa operación, son lanzados realizando las instrucciones que contienen.

ProcedureUn grupo de instrucciones con nombre (también llamados procedimientos almacenados), que puedeejecutarse llamando desde fuera de la base de datos o desde otro procedimiento o Trigger de la propia basede datos.

FUNDAMENTOS DEL LENGUAJE SQL

6

Page 19: Módulo_8_Acceso a bases de datos con ADO

3. Lenguaje de manipulación de datos (LMD)

Para establecer las condiciones que han de cumplir los registros sobre los que se vaya a actuar con estasinstrucciones, se ha de utilizar la cláusula WHERE, la cual admite la mayoría de los operadores que acontinuación se detallan.

Los modificadores, conectores, operadores, funciones de ordenación y agregación utilizables en lasinstrucciones anteriores son:

DISTINCT: Para devolver valores únicos si hay duplicados.TOP: Para limitar el número de registros devueltos.EXIST: Para verificar la existencia de un valor.SOME: Para saber si hay alguna ocurrencia del valor.ANY: Para cualquiera de los registros que cumplan la condición.ALL: Para recuperar todos los registros que cumplan la condición.CONTAINS: Para verificar que una cadena contiene un valor.AND: “Y” lógico, ambas condiciones.OR: “O” lógico, alguna de las condiciones.NOT: “NO” lógico, lo contrario de lo indicado por la condición.IN: Para verificar contra una lista de valores.BETWEEN: Para validar contra un rango de valores.LIKE: Para validar cadenas parciales.% - : Cadena, sustitución de cualquier carácter, el número de veces que sea._ - : Carácter, sustitución de un carácter individual.+ , Suma.- , Resta.* , Multiplicación./ , División.ORDER BY ASC: Ordenación ascendente.ORDER BY DESC: Ordenación descendente.COUNT( ): Contar ocurrencias.MIN( ): Valor mínimo de la expresión en el conjunto de resultados.MAX( ): Valor máximo de la expresión en el conjunto de resultados.SUM( ): Suma de los valores de la expresión en el conjunto de resultados.AVG( ): Promedio de los valores de la expresión en el conjunto de resultados.JOIN:, Producto cartesiano de la unión de dos tablas.LEFT JOIN: Unión de todos los registros de la tabla de la izquierda con los correspondientes de la tabla

de la derecha.RIGHT JOIN: Operación inversa de la anterior.INNER JOIN: Sólo une los registros coincidentes.

FUNDAMENTOS DEL LENGUAJE SQL

7

Page 20: Módulo_8_Acceso a bases de datos con ADO

UNION: Une los registros de dos conjuntos de resultados, con la misma estructura.INTERSECT: Intersección de dos conjuntos de resultados.MINUS: Resta de dos conjuntos de resultados.

El Lenguaje de Manipulación de Datos (LMD) se utiliza en los programas, enlos famosos Command, o desde la consola de la base de datos, para actuarsobre los mismos.

Las instrucciones del lenguaje de manipulación de datos son las siguientes:

SELECT: Para recuperar datos de la base de datos, de una o más tablas o vistas.INSERT: Para añadir registros a una o más tablas.UPDATE: Para modificar el contenido de una o más tablas.DELETE: Para eliminar un grupo de registros.

Sintaxis básica

Vamos a conocer ahora la sintaxis básica de las principales instrucciones estudiadas hasta ahora:

SELECT [ALL | DISTINCT] <listaSelección>FROM {<tablaOrigen>} [WHERE <condiciónBúsqueda>]

INSERT [INTO]{nombreTabla | nombreVista} {[(listaColumnas)]{VALUES ({DEFAULT | NULL| expresión}[,…n])| DEFAULT VALUES

UPDATE {nombreTabla | nombreVista}SET {nombreColumna = {expresión | DEFAULT | NULL} |@variable = expresión}[, …n]WHERE {condicionesBúsqueda}

DELETE [FROM] {nombreTabla|nombreVista}WHERE condicionesBúsqueda

FUNDAMENTOS DEL LENGUAJE SQL

8

Page 21: Módulo_8_Acceso a bases de datos con ADO

4. Triggers

Son parecidos a los procedimientos almacenados en que contienen un paquete de instrucciones ejecutablesy se almacenan en la base de datos con un nombre asociado.

Normalmente tienen:

- Una sección declarativa.- Una sección de instrucciones ejecutables.- Y, finalmente, la de control de excepciones, casi como pequeños programas.

El lanzamiento de su ejecución (disparo) es automático, siempre que se produzca la acción a la que estánasociados (INSERT, UPDATE o DELETE).

Pero para ello no sólo vale el declararlos, también han de ser activados, y para ello se ha de utilizar una deestas sintaxis (según se quiera activarlo o desactivarlo).

ALTER TRIGGER nombre_trigger ENABLE;ALTER TRIGGER nombre_trigger DISABLE;

Utilidad de Triggers

Los Triggers sirven para:

- Mantener restricciones de integridad complejas. Es decir, para que si actuamos sobre una tabla, elTrigger modifique automáticamente las tablas que dependan de ésta.

- La auditoría de la información contenida en una tabla. Es decir, registrar los cambios realizados sobreuna tabla, insertando está información en tablas temporales o de historial así como registrar quiény cuándo realizó esos cambios.

- Avisar automáticamente a otros programas de que se han producido cambios en una tabla para querespondan con una determinada acción.

FUNDAMENTOS DEL LENGUAJE SQL

9

Page 22: Módulo_8_Acceso a bases de datos con ADO

Sintaxis Básica

CREATE [OR REPLACE] TRIGGER nombre_trigger BEFORE | AFTER [INSERT, DELETE o UPDATE] ON nombre_tabla [FOR EACH ROW [WHEN condición_disparo]]

Cuerpo del disparador;END nombre_trigger;

En el cuerpo del Trigger se codifican sentencias del lenguaje de manipulación de datos o del lenguaje dedefinición de datos, según la función que deba cumplir el mismo.

Ejemplos de base de datos de Microsoft

Ahora veremos unos ejemplos que utilizan una base de datos de muestra de Microsoft “AdventureWorks”, lacual se puede descargar de la página web de Microsoft, si se desea ejecutar estos ejercicios.

1. Primero una selección sencilla de los primeros 10 registros de contactos, seleccionando unos pocos camposde la tabla.

FUNDAMENTOS DEL LENGUAJE SQL

10

Page 23: Módulo_8_Acceso a bases de datos con ADO

2. Cruzar dos tablas mediante el índice, pero con una condición sobre un campo que no es del índice y en lasegunda tabla.

3. Modificación sobre un registro existente.

4. Eliminar un registro, aunque, por un tema de restricciones de integridad, en este caso no se ejecute.

FUNDAMENTOS DEL LENGUAJE SQL

11

Page 24: Módulo_8_Acceso a bases de datos con ADO

5. Crear una vista.

6. Y así se utilizaría.

FUNDAMENTOS DEL LENGUAJE SQL

12

Page 25: Módulo_8_Acceso a bases de datos con ADO

5. Resumen

Has llegado al final de esta lección de formación que denominamos “Fundamentos del Lenguaje SQL”.En esta lección hemos estudiado los siguientes contenidos:

FUNDAMENTOS DEL LENGUAJE SQL

13

Page 26: Módulo_8_Acceso a bases de datos con ADO

EL GESTOR DE BASE DE DATOS

SQL SERVER

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 27: Módulo_8_Acceso a bases de datos con ADO

Características

Las herramientas comerciales para manejar bases de datos relacionales sedenominan Sistemas Gestores de Bases de Datos Relacionales, por sus siglasSGBDR.

Microsoft también tiene el suyo, en este caso llamado SQL Server, un nombrebastante neutro y que indica claramente la finalidad del mismo.

Dentro de SQL, Microsoft ha incluido utilidades, complementos y herramientas que lo convierten en algomás que un gestor de base de datos.

Utilidades, Complementos y Herramientas de SQL Server

Entorno GráficoPermite toda la gestión de la base de datos incluida en los lenguajes de definición y manipulación de datosen un entorno similar al IDE de Visual Studio, IntelliSense incorporado. Es decir, cuando se empieza a teclearun comando, instrucción o nombre de objeto, va sugiriendo el resto y cuando se está dentro de undeterminado objeto, sugiere sus componentes, inclusive los nombres de campos de las tablas o vistas, lo cualfacilita enormemente la tarea y evita los típicos errores al teclear.

Query Services:Servicios de Consulta.

Analysis Services: Servicios de análisis. Totalmente enfocado al mundo del DataWarehouse y Business Inteligence, que no sonobjeto de este curso, pero que versan sobre el análisis de la información con diferentes formatos depresentación y DataMining.

EL GESTOR DE BASE DE DATOS SQL SERVER

2

Page 28: Módulo_8_Acceso a bases de datos con ADO

Reporting Services:Servicios de Informes a Medida. Éstos cuentan con un amplio surtido de posibilidades gráficas para analizarla información, sin llegar a las capacidades de los Analysis Services. Se prevé que en un futuro, no demasiadolejano, estos dos servicios acabarán fusionados.

Integration Services: Servicios de Integración. Están enfocados a generar un interfaz único de acceso a los datos de una compañía,a partir de orígenes de datos múltiples y diversos.

Synch Services: Servicios de Sincronización. Se orientan a que los usuarios de la organización, sea cual sea su dispositivo deentrada o plataforma, tengan siempre la información relevante adecuadamente actualizada, aunque seconecten sólo en ocasiones a los servidores de la organización.

Search Services: Servicios de Búsqueda. SQL incorpora un potente motor de búsquedas. Tiene, incluso, la posibilidad debúsquedas de texto en los campos de la base de datos, pagando el precio de la correspondiente indexaciónde los contenidos. Con lo que es muy conveniente valorar el uso que se vaya a dar a esta utilidad antes deponerla en marcha, ya que llega a tener un impacto sobre el rendimiento general de la base de datos.

Capacidad de administración: Cuenta con un sistema basado en políticas, lo mismo que el famoso Active Directory, ya que dispone deherramientas para la monitorización del rendimiento, solución de problemas, y configuración.

Spatial Data: Datos Espaciales. Ahora se permite el almacenamiento de coordenadas espaciales, las cuales facilitan lageolocalización de la información almacenada en la base de datos.

Powerful Programmability: Conocida también como Programabilidad de Datos. Se refiere a la facilidad que reviste programar en y contralas bases de datos contenidas en el gestor. En, mediante el Lenguaje Transac SQL, una versión específica quepermite una gran variedad de comandos, sentencias y variables, además de un conjunto reducido deinstrucciones de control y bucle. Y contra, mediante la integración plena con el .NET Framework y el soportea Ado.NET Entity Framework, además del soporte a casi cualquier tipo de dato, incluidos datos binarios comolas imágenes, eliminando las limitaciones de las versiones anteriores. Y, lo más interesante es el nuevoLanguage Integrated Query (LINQ) o Lenguaje de Consulta Integrado, el cual va empapado en los lenguajessoportados por el .NET Framework, a partir de la versión 3.5, y que permite utilizar sentencias de SQLdirectamente integradas en el código, sin la obligación del uso de los objetos típicos de acceso adatos de ADO.NET.

EL GESTOR DE BASE DE DATOS SQL SERVER

3

Page 29: Módulo_8_Acceso a bases de datos con ADO

Seguridad: El nivel de control del que dispone es muy alto. Hay muchos aspectos que especificar en las herramientasaunque también existen opciones por defecto más fáciles de usar y que ayudan a conseguir sistemas de altorendimiento con un nivel de protección desconocido hasta ahora. Tienen herramientas para el control deaccesos, encriptación de los datos y auditoría permanente.

Resumen

Has llegado al final de esta lección de formación que denominamos “El Gestor de Base de Datos SQL Server”.En esta lección hemos estudiado los siguientes contenidos:

El Gestor de Base de Datos SQL Server

El Sistema Gestor de Bases de Datos Relacionales de Microsoft se llama SQL Server y en su últimaversión SQL Server 2008, incorpora muchos complementos y servicios que lo convierten en algomás que un gestor de bases de datos.

EL GESTOR DE BASE DE DATOS SQL SERVER

4

Page 30: Módulo_8_Acceso a bases de datos con ADO

ACCESO A BASE DEDATOS CON

ADO.NET

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 31: Módulo_8_Acceso a bases de datos con ADO

ÍNDICE

ACCESO A BASE DE DATOS CON ADO.NET

5. ACCESO A DATOS EN MODO CONECTADO

5.1 – Conexión con una base de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3

5.2 – Manipulación de datos con DataReader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7

5.3 – Ejecución de procedimientos almacenados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11

5.4 - Transacciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16

Page 32: Módulo_8_Acceso a bases de datos con ADO

5.1 – Conexión con una base de datos.

Bueno, continuamos con el acceso a datos, ahora se trata de empezar a ver en serio cómo te puedes conectaruno a una base de datos y trabajar con ella, de momento a la manera tradicional, es decir en modoconectado. Vayamos por pasos y no quieras correr directamente a las últimas tecnologías existentes.

Por lo que ya vimos en un módulo anterior vamos a necesitar varios objetos para poder efectuar esa conexión,por si acaso te refresco el cuadro resumen y así no has de navegar para encontrarlo.

En este caso vamos a centrarnos en la utilización del bloque que te resalto.

De lo que se deduce que necesitaremos:

- Una base de datos contra la que trabajar, en este caso nos serviremos de la misma que vimos en losejemplos de los temas SQL Server “AdventureWorks”.

- Una conexión contra esa base de datos, lógicamente, si no le indicamos al programa contra quién hade trabajar y a la base de datos con que usuario queremos entrar, difícil estará que se comuniquen.

- Un comando en el que registrar y luego ejecutar las sentencias de recuperación de datos que nosinteresen.

- Finalmente, un DataReader para cargar esos datos y, mediante nuestra manipulación delmismo en el código, mostrarlos por pantalla.

ACCESO A BASE DE DATOS CON ADO.NET

3

Page 33: Módulo_8_Acceso a bases de datos con ADO

Dado que la base de datos a la que tenemos la intención de acceder está en SQL Server, necesitaremos lasversiones específicas para SQL de dichos objetos, por lo que deberemos importar a nuestro código el espaciode nombres correspondiente ¿te acuerdas de cuál es? Por si acaso te lo recuerdo yo System.Data.SqlClient,pero además, para disponer de los objetos genéricos que requerirán las definiciones previas, es interesanteimporte el espacio de nombres de nivel anterior, o sea System.Data, luego verás el porqué.

Una instrucción de bloque de Visual Basic que hasta ahora no te había comentado adecuadamente es laUsing…EndUsing.

Esta instrucción de bloque, aparte de permitir el acceso directo a los componentes de un objeto, sincalificarlos con éste, asegura que los recursos ocupados por dicho objeto se liberan al finalizar el bloque, silo creamos en la instrucción Using, como verás más adelante.

Puede parecerte trivial, pero tiene bastante importancia de cara a la memoria del equipo, cuantos másrecursos seas capaz de liberar, mejor irá la máquina.

Además, una vez finalizado el bloque de utilización, el objeto, normalmente, ya no tiene utilidad, con lo quees una costumbre muy sana el tomar este hábito higiénico en tu codificación.

Bueno, una vez puesto en antecedentes te voy a mostrar el código necesario para establecer una conexióncon una base de datos.

‘ Las importaciones comentadasImports SystemImports System.DataImports System.Data.SqlClient

Module Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentes‘ DataSource: indica el origen de los datos o proveedor de ‘ datos‘ Initial Catalog: es el nombre de la base de datos concreta ‘ contra la que quieres trabajar‘ Integrated security: es el tipo de acceso, en este caso, ‘ seguridad integrada de Windos, pero podría ser usuario y ‘ contraseña, aunque es bastante menos seguro

ACCESO A BASE DE DATOS CON ADO.NET

4

Page 34: Módulo_8_Acceso a bases de datos con ADO

Dim connectionString As String = _“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)‘ Inicio del bloque Using comentado, con la creación de la‘ conexión SQL

Using connection As New SqlConnection(connectionString)

· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

‘ Bolque Try para poder capturar las posibles excepciones ‘ que se produzcan y controlarlas sin casque de programaTry

‘ Se abre la conexiónconnection.Open()

· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

‘ Aquí irá el código que utilice la conexión· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

Catch ex As Exception‘ Si se produce alguna excepción, lo notificamosConsole.WriteLine(ex.Message)

End TryEnd Using‘ Fin del bloque Using, aquí desaparece la conexión

‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)

‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

5

Page 35: Módulo_8_Acceso a bases de datos con ADO

Como puedes ver he incluido los comentarios en el código, para que veas las cosas en su sitio.

No es demasiado complicado ¿verdad?

Quizás lo más peliagudo sea el tema de la cadena de conexión (ConnectionString), pero no te preocupes,raramente la vas a tener que definir.

Por una parte, si la has de codificar en duro, tal y como aquí figura, será copiar y pegar, como hacemostodos y sustituir aquello que lo requiera, ya que esta es una versión muy resumida.

Segundo, porque la mayor parte de las veces la incluirás desde el propio IDE de Visual Studio, mediante elcorrespondiente interfaz gráfico, con lo que será seleccionar pinchando y Visual Studio se encargará degenerar la cadena de conexión y colocarla en el archivo de configuración asociado a toda solución de .NETFramework.

Por lo demás, se declara el objeto de conexión en el Using, como ya hemos comentado, utilizando la claseespecífica de conexión SQL y, dentro de un bloque Try, por supuesto, se ejecuta el Open de la conexión. Nadamás sencillo ¿no?

En el siguiente apartado veremos cómo podemos utilizar esta conexión, una vez la tenemos ya establecida.

Por cierto, estoy utilizando un programa de consola para hacértelo más fácil y no añadir, de momento, otrascomplicaciones, más adelante veremos esto aplicado a programas de formularios Windows, no te preocupes.

ACCESO A BASE DE DATOS CON ADO.NET

6

Page 36: Módulo_8_Acceso a bases de datos con ADO

5.2 – Manipulación de datos con DataReader.

Bueno, continuamos para bingo, ahora toca ya empezar a utilizar esa conexión abierta para hacer algo conella.

Y, por aquello de la familiaridad, vamos a ejecutar uno de los ejemplos que ya vimos en el temario de SQLcontra la base de datos “AdventureWorks”, así verás cómo puedes obtener lo mismo desde programa quedesde la consola de SQL.

Par usar la conexión necesitaremos, como ya hemos comentado, un objeto del tipo Command.

Para rellenar este Command, no es obligatorio pero si recomendable, se utiliza un objeto de tipo String, enel que construimos la sentencia.

En este caso se podría haber codificado directamente, pero la mayoría de las veces, las sentencias queutilizamos son bastante largas y se forman concatenando texto y variables, con lo que el tema de comillasse puede llegar a complicar si lo intentamos meter todo de una vez. El uso habitual es incluso un poco másaparentemente enrevesado que el que ves aquí, ya que utilizamos un StringBuilder, para ir haciendo lasconcatenaciones y luego lo pasamos como String al texto del Command.

Lógicamente, si lo que queremos es leer datos de la base de datos, de ahí el Select de la sentencia, y estamosen la unidad didáctica de acceso a datos en modo conectado, necesitaremos un objeto DataReader pararecuperar el resultado de la ejecución del comando. Por supuesto, como estamos atacando una base dedatos SQL, éste deberá ser el específico SqlDataReader.

El objeto Command tiene varios métodos para la ejecución de la sentencia, que van en función del tipo deresultado esperado: ExecuteNonQuery: para sentencias que no devuelvan datos, como una actualización de datos.ExecuteReader: para recuperar datos de la base de datos.ExecuteScalar: para recuperar un valor único, como podría ser un contador o un código de retorno de unprocedimiento almacenado.ExecuteXMLReader: para la lectura de datos almacenados en ficheros XML.

ACCESO A BASE DE DATOS CON ADO.NET

7

Page 37: Módulo_8_Acceso a bases de datos con ADO

‘ Las importaciones comentadasImports SystemImports System.DataImports System.Data.SqlClient

Module Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentes‘ DataSource: indica el origen de los datos o proveedor de ‘ datos‘ Initial Catalog: es el nombre de la base de datos concreta ‘ contra la que quieres trabajar‘ Integrated security: es el tipo de acceso, en este caso, ‘ seguridad integrada de Windos, pero podría ser usuario y ‘ contraseña, aunque es bastante menos seguroDim connectionString As String = _

“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)

‘ Inicio del bloque Using comentado, con la creación de la‘ conexión SQLUsing connection As New SqlConnection(connectionString)

‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()

‘ Definimos la sentencia que vamos a aejecutarDim queryString As String = _

“SELECT TOP 10 [ContactID],[FirstName],[LastName]“ & _“, [Phone] FROM [Person].[Contact];”

‘ Asignamos la sentencia al comandocommand.CommandText = queryString

‘ Bolque Try para poder capturar las posibles excepciones

ACCESO A BASE DE DATOS CON ADO.NET

8

Page 38: Módulo_8_Acceso a bases de datos con ADO

‘ que se produzcan y controlarlas sin casque de programaTry

‘ Se abre la conexiónconnection.Open()

Console.WriteLine(“Conexión establecida, “ & _“leyendo los datos”)

‘ Carga el resultado de la ejecución del comando en ‘ un nuevo DataReaderDim dataReader As SqlDataReader =

command.ExecuteReader()

‘ Bucle de lectura hasta fin de registrosDo While dataReader.Read()

Console.WriteLine(vbTab & dataReader(0) & _vbTab & dataReader(1) & vbTab & _dataReader(2))

Loop

‘ Se cierra el DataReader para evitar error en el ‘ End UsingdataReader.Close()

Catch ex As Exception‘ Si se produce alguna excepción, lo notificamosConsole.WriteLine(ex.Message)

End TryEnd Using‘ Fin del bloque Using, aquí desaparece la conexión

‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)

‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

9

Page 39: Módulo_8_Acceso a bases de datos con ADO

Ahora el resultado de la ejecución de este código sería.

Como ves obtenemos lo mismo que antes desde la consola de SQL.

Lo único que no habías visto aún es la palabra clave vbTab, que aquí se usa en el Console.WriteLine(), y quesirve para insertar una tabulación, de esta forma los datos se presentan un poco alineados, aunque como hayalgún nombre largo, queda un poco descuajeringado, pero escribiendo en consola no se puede hacer muchomás.

ACCESO A BASE DE DATOS CON ADO.NET

10

Page 40: Módulo_8_Acceso a bases de datos con ADO

5.3 – Ejecución de procedimientos almacenados.

Los procedimientos almacenados, como ya vimos en el módulo de dicado a SQL, son grupos de sentencias SQL,almacenadas con nombre en la propia base de datos, que sirven para ejecutar tareas repetitivas o decodificación complicada, admitiendo parámetros de entrada y salida, además de los resultados que puedanproporcionar.

Es decir, si una tarea habitual en tu base de datos es la de añadir la información de un cliente, y estainformación se halla dispersa por un sinnúmero de tablas, relacionadas o no entre sí y con restricciones deexistencia cruzadas, la creación correcta de toda la información puede llegar a ser complicada. Por ello, eldiseñador de la base de datos establece cómo se ha de generar esta información, se desarrolla elcorrespondiente procedimiento almacenado, el cual recibirá como parámetros todos los datos que necesite,y efectuará la creación ordenada de los registros pertinentes, con sus dependencias y relaciones. Con lo quecada vez que se necesite crear un cliente, desde cualquier parte de los programas, sólo habrá que hacer unallamada al procedimiento almacenado y pasarle sus parámetros, sin tener que reinventar la rueda a cada vezy asegurándote de que no vayan a haber errores ni inconsistencias en la base de datos.

También es un sistema válido a la hora de recuperar información elaborada a partir de varias tablas, si elalgoritmo de búsqueda no es evidente o si implica varias tareas de creación de tablas temporales intermedias,es preferible tenerlo todo desarrollado y probado sólo una vez y guardado en la propia base de datos quetener que generar y probar el código cada vez que se necesite, sin estar seguro de que cada desarrolladorhaya tenido en cuenta todas las posibles variantes y de que el resultado ofrecido sea el correcto.

Otro uso habitual de los procedimientos almacenados es de mantenimiento de la propia base de datos, tantodesde el punto de vista del administrador como del programador. Siempre hay tareas de limpieza y depuraciónde datos que se pueden automatizar, con lo que se abunda en la seguridad e integridad. Encima, este tipode procedimientos de mantenimiento se pueden programar y la propia base de datos se encargaría delanzarlos en el momento de menor carga, registrando, opcionalmente, el resultado en un archivo de log. Conlo que el administrador sólo tendría que verificar en dicho log si todo ha funcionado correctamente.

Para el ejemplo vamos a utilizar un procedimiento almacenado ya existente en la base de datos“AdventureWorks”, que estamos utilizando de base de ejemplos, concretamente el “uspGetBillOfMaterials”.Te incluyo el código del mismo, no para que te lo estudies a fondo, ya que no tiene sentido al no conocer labase de datos, pero si para que veas el nivel de complejidad del código del mismo, tal y como hemoscomentado antes. ¿Te imaginas tener que codificar esto cada vez que necesitaras recuperar esta información?De esta forma, con pasarle los parámetros indicados, que son la identificación del producto y la fecha límitede vigencia de los sub-productos obtendremos la lista de componentes del mismo, y, de propina, un códigode retorno que nos indicará si todo ha funcionado correctamente o si se ha producido algún tipo de problema.

ACCESO A BASE DE DATOS CON ADO.NET

11

Page 41: Módulo_8_Acceso a bases de datos con ADO

/****** Object: StoredProcedure [dbo].[uspGetBillOfMaterials] Script Date: 11/21/200809:23:11 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [dbo].[uspGetBillOfMaterials]

@StartProductID [int],@CheckDate [datetime]

ASBEGIN

SET NOCOUNT ON;— Use recursive query to generate a multi-level Bill of Material (i.e. all level 1 — components of a level 0 assembly, all level 2 components of a level 1 assembly)— The CheckDate eliminates any components that are no longer used in the product on this

date.WITH [BOM_cte]([ProductAssemblyID], [ComponentID], [ComponentDesc], [PerAssemblyQty],

[StandardCost], [ListPrice], [BOMLevel], [RecursionLevel]) — CTE name and columnsAS (

SELECT b.[ProductAssemblyID], b.[ComponentID], p.[Name], b.[PerAssemblyQty],p.[StandardCost], p.[ListPrice], b.[BOMLevel], 0 — Get the initial list of components for the bikeassembly

FROM [Production].[BillOfMaterials] bINNER JOIN [Production].[Product] p ON b.[ComponentID] = p.[ProductID]

WHERE b.[ProductAssemblyID] = @StartProductID AND @CheckDate >= b.[StartDate] AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate)

UNION ALLSELECT b.[ProductAssemblyID], b.[ComponentID], p.[Name], b.[PerAssemblyQty],

p.[StandardCost], p.[ListPrice], b.[BOMLevel], [RecursionLevel] + 1 — Join recursive member toanchor

FROM [BOM_cte] cteINNER JOIN [Production].[BillOfMaterials] b ON b.[ProductAssemblyID] = cte.[ComponentID]INNER JOIN [Production].[Product] p

ACCESO A BASE DE DATOS CON ADO.NET

12

Page 42: Módulo_8_Acceso a bases de datos con ADO

ON b.[ComponentID] = p.[ProductID] WHERE @CheckDate >= b.[StartDate]

AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate))

— Outer select from the CTESELECT b.[ProductAssemblyID], b.[ComponentID], b.[ComponentDesc],

SUM(b.[PerAssemblyQty]) AS [TotalQuantity] , b.[StandardCost], b.[ListPrice], b.[BOMLevel],b.[RecursionLevel]

FROM [BOM_cte] bGROUP BY b.[ComponentID], b.[ComponentDesc], b.[ProductAssemblyID], b.[BOMLevel],

b.[RecursionLevel], b.[StandardCost], b.[ListPrice]ORDER BY b.[BOMLevel], b.[ProductAssemblyID], b.[ComponentID]OPTION (MAXRECURSION 25)

END;

Te lo he puesto tal cual, sin traducir ni nada ya que nos es objeto de este curso el que desarrolles este tipode procedimientos, pero creo que se entiende bastante bien.

Bueno pues, si ahora incorporamos la ejecución de este procedimiento almacenado en nuestro programa deconsola, ya sé que la salida no es muy espectacular, pero es mucho más sencillo de ver el código exclusivodel lanzamiento de esta forma.

Imports SystemImports System.DataImports System.Data.SqlClient

Module Module1Public Sub Main()

Dim connectionString As String = _“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)

Using connection As New SqlConnection(connectionString)

ACCESO A BASE DE DATOS CON ADO.NET

13

Page 43: Módulo_8_Acceso a bases de datos con ADO

‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()

‘ Asignamos el tipo al comando y el procedimientpcommand.CommandType = CommandType.StoredProcedurecommand.CommandText = “dbo.uspGetBillOfMaterials”

‘ Asignamos valores a sus parámetroscommand.Parameters.Add(“@StartProductID”, & _

SqlDbType.Int).Value = 514command.Parameters.Add(“@CheckDate”, & _

SqlDbType.DateTime).Value = New DateTime(2008, 12, 31)

Tryconnection.Open()Console.WriteLine(“Conexión establecida, “ & _

“leyendo los datos”)Dim dataReader As SqlDataReader = & _

command.ExecuteReader()Do While dataReader.Read()

Console.WriteLine(vbTab & dataReader(0) & _vbTab & dataReader(1) & _vbTab & dataReader(2) & _vbTab & dataReader(3) & _vbTab & dataReader(4) & _vbTab & dataReader(5) & _vbTab & dataReader(6) & _vbTab & dataReader(7))

LoopdataReader.Close()

Catch ex As ExceptionConsole.WriteLine(ex.Message)

End TryEnd Using

Console.WriteLine(“Conexión cerrada”)Console.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

14

Page 44: Módulo_8_Acceso a bases de datos con ADO

Como ves, no es para tanto, se define el Command casi de la misma forma, en lugar de asignar la sentenciaSQL a su texto, se le asigna el nombre del procedimiento almacenado, tras decirle, en su tipo, que esprocedimiento almacenado. Quizás lo más complicado sea la asignación de parámetros. Una peculiaridad esque debes saber cuáles son los parámetros y el tipo de dato de los mismos para asignarlos, pero creo que esbastante normal, si vas a usar una herramienta, debes saber por qué lado la has de coger y cómo se utiliza¿no?

Por lo demás su comportamiento, a la hora de asignarlo al DataReader y operar con éste es idéntico alejemplo anterior.

Y al pulsar F5 para ejecutar nuestro programa obtenemos lo siguiente:

ACCESO A BASE DE DATOS CON ADO.NET

15

Page 45: Módulo_8_Acceso a bases de datos con ADO

5.4 - Transacciones.

Bueno, vamos a por el último apartado de esta unidad didáctica, si te parece, es el referente a lastransacciones.

Ya las habíamos comentado por encima, pero ahora nos vamos a meter un poco más a fondo con ellas.

Una transacción es el nombre que se le da a un paquete de operaciones consecutivas efectuadas contra unabase de datos para asegurar la integridad de los mismos.

Me explico, y nada mejor que un ejemplo, imagínate cualquier empresa, con sus clientes, cartera de pedidosy contabilidad. Cuando llega final de mes hay que lanzar la facturación. Esto implica que habrá que acumularlos pedidos ya entregados pendientes de facturar, elaborar la correspondiente factura, generar el registrode la misma en la contabilidad y actualizar el saldo pendiente del cliente. ¿Hasta aquí bien, no? Nada nuevobajo el sol. EL problema puede ser que en medio de estas operaciones ocurra cualquier tipo de problema conlos ordenadores, con lo que, si efectuáramos las operaciones de forma individual y consecutiva, nospodríamos quedar con los pedidos marcados como facturados y la factura sin registrar, o ésta registrada perosin generar los asientos contables o …etc. Las posibilidades de casque son infinitas, como los caminos delSeñor.

La única forma de garantizar que todo funcione correctamente y no tengamos un sistema con inconsistenciade datos es el utilizar transacciones.

En este caso, por cada cliente tratado, iniciaríamos una transacción, con lo que todas las operaciones queefectuáramos, dentro de dicha transacción, contra la base de datos se irían registrando en un archivoespecial. Al finalizar el paquete completo, le diríamos a la transacción que hiciera un Commit, si todo ha idobien o un Rollback en caso contrario.

El Commit haría que se marcarán como efectuadas y correctas todas las modificaciones aportadas a la basede datos, moviendo el puntero de movimientos completados de ese archivo especial a justo después delúltimo de los registros de dicha transacción.

En cambio el Rollback, cogería e iría deshaciendo cada uno de los registros de la transacción hasta encontrarel último punto de Commit correcto, dejando la base de datos en la situación estable con la que empezó latransacción.

¿Está claro?

Para poder utilizar transacciones hay que importar el espacio de nombres System.Transactions, para disponerde los objetos asociados a DbTransaction, como código genérico y luego utilizar las específicas del proveedorde datos que estemos utilizando.

Y la forma de utilizarlas tiene un varias opciones, como siempre, una de ellas, la más recomendada,es similar al uso que hemos hecho de la conexión en el ejemplo anterior, es decir crear la transacciónen un Using, con lo cual todo el código relacionado con la misma iría dentro del bloque, si añadimos

ACCESO A BASE DE DATOS CON ADO.NET

16

Page 46: Módulo_8_Acceso a bases de datos con ADO

un bloque Try, podremos codificar el Rollback en el/los Catch asociado/s al mismo y asegurarnos que todoestá controlado.

Otra, que se recomienda cuando hay muchas tablas implicadas, es el uso dentro de un procedimientoalmacenado, utilizando los comandos Transact SQL: BEGIN TRANSACTION, COMMIT TRANSACTION y ROLLBACKTRANSACTION.

La otra forma de utilizar transacciones en nuestro código es mediante el uso de los objetos Connection yCommand, para variar.

Iniciaríamos la transacción con el método BeginTransaction del objeto Connection del proveedor de datos queestemos utilizando y la finalizaríamos con los métodos Commit o Rollback del mismo objeto.

Luego el objeto de tipo Transaction obtenido con el BeginTransaction se asigna a la propiedad Transactiondel Command y después ya se pueden ir ejecutando distintas sentencias con el Command, debiendo ejecutaruno de los dos métodos de cierre para finalizar las operaciones.

Como ya hemos comentado, lo adecuado es meter las operaciones de la transacción en un bloque Try, ya quelas posibilidades de problemas en algún punto son muy altas y añadir, por lo tanto, el correspondienteRollback en el Catch asociado, en todos si hay más de uno. Pero este Rollback también tiene que ir dentrode su propio bloque Try, ya que siempre es posible que con el error que ha hecho saltar el Catch, el propiogestor de la base de datos haya efectuado su propio Rollback o que la conexión se haya perdido, y un segundoRollback resultaría en un error.

Vamos a ver esto en un ejemplo, a ver si queda más claro.

Situación inicial de los datos, no hay provincia para España.

ACCESO A BASE DE DATOS CON ADO.NET

17

Page 47: Módulo_8_Acceso a bases de datos con ADO

Generamos pues el código para insertar un par de provincias, con una transacción para asegurar que seinserten ambas.

Imports SystemImports System.DataImports System.Data.SqlClientImports System.TransactionsModule Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentesDim connectionString As String = _

“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Using connection As New SqlConnection(connectionString)connection.Open()‘ Iniciamos una transacción contra el objeto ConnectionDim sqlTran As SqlTransaction = _

connection.BeginTransaction()Console.WriteLine(“Iniciada la transacción”)‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()command.Transaction = sqlTranTry

‘ Insertamos un par de registros‘ Definimos la sentencia SQL a ejecutar‘ primero la parte fija

Dim sql1 As String = “INSERT INTO Person.StateProvince (StateProvinceCode,CountryRegionCode, IsOnlyStateProvinceFlag, Name, TerritoryID) “

‘ Aquí la parte variable por registroDim sql2 As Stringsql2 = “VALUES(‘VI ‘,’ES ‘, 0, ‘Alava’, 7)“Dim sql As String = sql1 & sql2‘ La asignamos al comandocommand.CommandText = sqlcommand.ExecuteNonQuery()

ACCESO A BASE DE DATOS CON ADO.NET

18

Page 48: Módulo_8_Acceso a bases de datos con ADO

‘ Segundo registrosql2 = “VALUES(‘AB’,’ES’, 0, ‘Albacete’, 7)“sql = sql1 & sql2‘ La asignamos al comandocommand.CommandText = sqlcommand.ExecuteNonQuery()‘ Commit de la transacciónsqlTran.Commit()Console.WriteLine(“Se han añadido los registros.”)

Catch ex As ExceptionConsole.WriteLine(ex.Message)Try

‘ Intenta hacer el Rollback a la transacción.sqlTran.Rollback()

Catch exRollback As Exception‘ Si falla, muestra el errorConsole.WriteLine(exRollback.Message)

End TryEnd Try

End Using‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

Creo que habla por si mismo ¿no?

Está claro que el tema de la sentencia de inserción se podría haber solucionado de una forma más elegante,por ejemplo con parámetros, que habría sido lo correcto, pero no te quería complicar las cosas.

Siempre hay que tener mucho cuidado con el tema de las comillas, al SQL sólo le gustan las comillas simples,y éstas, dentro de las dobles, no requieren duplicidad, te lo digo porque yo siempre pico y me toca corregir.

ACCESO A BASE DE DATOS CON ADO.NET

19

Page 49: Módulo_8_Acceso a bases de datos con ADO

Bueno, si pulsamos F5.

Y si comprobamos en la base de datos:

ACCESO A BASE DE DATOS CON ADO.NET

20

Page 50: Módulo_8_Acceso a bases de datos con ADO

EN RESUMEN

Hemos visto la utilización de los objetos Connection, Command, DataReader para el acceso adatos mediante ADO.NET de forma conectada.

También hemos visto cómo se pueden utilizar procedimientos almacenados con la misma técnica.

Finalmente, hemos visto cómo utilizar transacciones desde nuestro código, mediante el objetoTransaction de la conexión y los métodos BeginTransaction, Commit y Rollback de la misma.

ACCESO A BASE DE DATOS CON ADO.NET

21

Page 51: Módulo_8_Acceso a bases de datos con ADO

ACCESO A BASE DEDATOS CON

ADO.NET

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 52: Módulo_8_Acceso a bases de datos con ADO

ÍNDICE

ACCESO A BASE DE DATOS CON ADO.NET

5. ACCESO A DATOS EN MODO CONECTADO

5.1 – Conexión con una base de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3

5.2 – Manipulación de datos con DataReader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7

5.3 – Ejecución de procedimientos almacenados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11

5.4 - Transacciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16

Page 53: Módulo_8_Acceso a bases de datos con ADO

5.1 – Conexión con una base de datos.

Bueno, continuamos con el acceso a datos, ahora se trata de empezar a ver en serio cómo te puedes conectaruno a una base de datos y trabajar con ella, de momento a la manera tradicional, es decir en modoconectado. Vayamos por pasos y no quieras correr directamente a las últimas tecnologías existentes.

Por lo que ya vimos en un módulo anterior vamos a necesitar varios objetos para poder efectuar esa conexión,por si acaso te refresco el cuadro resumen y así no has de navegar para encontrarlo.

En este caso vamos a centrarnos en la utilización del bloque que te resalto.

De lo que se deduce que necesitaremos:

- Una base de datos contra la que trabajar, en este caso nos serviremos de la misma que vimos en losejemplos de los temas SQL Server “AdventureWorks”.

- Una conexión contra esa base de datos, lógicamente, si no le indicamos al programa contra quién hade trabajar y a la base de datos con que usuario queremos entrar, difícil estará que se comuniquen.

- Un comando en el que registrar y luego ejecutar las sentencias de recuperación de datos que nosinteresen.

- Finalmente, un DataReader para cargar esos datos y, mediante nuestra manipulación delmismo en el código, mostrarlos por pantalla.

ACCESO A BASE DE DATOS CON ADO.NET

3

Page 54: Módulo_8_Acceso a bases de datos con ADO

Dado que la base de datos a la que tenemos la intención de acceder está en SQL Server, necesitaremos lasversiones específicas para SQL de dichos objetos, por lo que deberemos importar a nuestro código el espaciode nombres correspondiente ¿te acuerdas de cuál es? Por si acaso te lo recuerdo yo System.Data.SqlClient,pero además, para disponer de los objetos genéricos que requerirán las definiciones previas, es interesanteimporte el espacio de nombres de nivel anterior, o sea System.Data, luego verás el porqué.

Una instrucción de bloque de Visual Basic que hasta ahora no te había comentado adecuadamente es laUsing…EndUsing.

Esta instrucción de bloque, aparte de permitir el acceso directo a los componentes de un objeto, sincalificarlos con éste, asegura que los recursos ocupados por dicho objeto se liberan al finalizar el bloque, silo creamos en la instrucción Using, como verás más adelante.

Puede parecerte trivial, pero tiene bastante importancia de cara a la memoria del equipo, cuantos másrecursos seas capaz de liberar, mejor irá la máquina.

Además, una vez finalizado el bloque de utilización, el objeto, normalmente, ya no tiene utilidad, con lo quees una costumbre muy sana el tomar este hábito higiénico en tu codificación.

Bueno, una vez puesto en antecedentes te voy a mostrar el código necesario para establecer una conexióncon una base de datos.

‘ Las importaciones comentadasImports SystemImports System.DataImports System.Data.SqlClient

Module Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentes‘ DataSource: indica el origen de los datos o proveedor de ‘ datos‘ Initial Catalog: es el nombre de la base de datos concreta ‘ contra la que quieres trabajar‘ Integrated security: es el tipo de acceso, en este caso, ‘ seguridad integrada de Windos, pero podría ser usuario y ‘ contraseña, aunque es bastante menos seguro

ACCESO A BASE DE DATOS CON ADO.NET

4

Page 55: Módulo_8_Acceso a bases de datos con ADO

Dim connectionString As String = _“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)‘ Inicio del bloque Using comentado, con la creación de la‘ conexión SQL

Using connection As New SqlConnection(connectionString)

· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

‘ Bolque Try para poder capturar las posibles excepciones ‘ que se produzcan y controlarlas sin casque de programaTry

‘ Se abre la conexiónconnection.Open()

· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

‘ Aquí irá el código que utilice la conexión· · · · · · · · ·· · · · · · · · ·· · · · · · · · ·

Catch ex As Exception‘ Si se produce alguna excepción, lo notificamosConsole.WriteLine(ex.Message)

End TryEnd Using‘ Fin del bloque Using, aquí desaparece la conexión

‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)

‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

5

Page 56: Módulo_8_Acceso a bases de datos con ADO

Como puedes ver he incluido los comentarios en el código, para que veas las cosas en su sitio.

No es demasiado complicado ¿verdad?

Quizás lo más peliagudo sea el tema de la cadena de conexión (ConnectionString), pero no te preocupes,raramente la vas a tener que definir.

Por una parte, si la has de codificar en duro, tal y como aquí figura, será copiar y pegar, como hacemostodos y sustituir aquello que lo requiera, ya que esta es una versión muy resumida.

Segundo, porque la mayor parte de las veces la incluirás desde el propio IDE de Visual Studio, mediante elcorrespondiente interfaz gráfico, con lo que será seleccionar pinchando y Visual Studio se encargará degenerar la cadena de conexión y colocarla en el archivo de configuración asociado a toda solución de .NETFramework.

Por lo demás, se declara el objeto de conexión en el Using, como ya hemos comentado, utilizando la claseespecífica de conexión SQL y, dentro de un bloque Try, por supuesto, se ejecuta el Open de la conexión. Nadamás sencillo ¿no?

En el siguiente apartado veremos cómo podemos utilizar esta conexión, una vez la tenemos ya establecida.

Por cierto, estoy utilizando un programa de consola para hacértelo más fácil y no añadir, de momento, otrascomplicaciones, más adelante veremos esto aplicado a programas de formularios Windows, no te preocupes.

ACCESO A BASE DE DATOS CON ADO.NET

6

Page 57: Módulo_8_Acceso a bases de datos con ADO

5.2 – Manipulación de datos con DataReader.

Bueno, continuamos para bingo, ahora toca ya empezar a utilizar esa conexión abierta para hacer algo conella.

Y, por aquello de la familiaridad, vamos a ejecutar uno de los ejemplos que ya vimos en el temario de SQLcontra la base de datos “AdventureWorks”, así verás cómo puedes obtener lo mismo desde programa quedesde la consola de SQL.

Par usar la conexión necesitaremos, como ya hemos comentado, un objeto del tipo Command.

Para rellenar este Command, no es obligatorio pero si recomendable, se utiliza un objeto de tipo String, enel que construimos la sentencia.

En este caso se podría haber codificado directamente, pero la mayoría de las veces, las sentencias queutilizamos son bastante largas y se forman concatenando texto y variables, con lo que el tema de comillasse puede llegar a complicar si lo intentamos meter todo de una vez. El uso habitual es incluso un poco másaparentemente enrevesado que el que ves aquí, ya que utilizamos un StringBuilder, para ir haciendo lasconcatenaciones y luego lo pasamos como String al texto del Command.

Lógicamente, si lo que queremos es leer datos de la base de datos, de ahí el Select de la sentencia, y estamosen la unidad didáctica de acceso a datos en modo conectado, necesitaremos un objeto DataReader pararecuperar el resultado de la ejecución del comando. Por supuesto, como estamos atacando una base dedatos SQL, éste deberá ser el específico SqlDataReader.

El objeto Command tiene varios métodos para la ejecución de la sentencia, que van en función del tipo deresultado esperado: ExecuteNonQuery: para sentencias que no devuelvan datos, como una actualización de datos.ExecuteReader: para recuperar datos de la base de datos.ExecuteScalar: para recuperar un valor único, como podría ser un contador o un código de retorno de unprocedimiento almacenado.ExecuteXMLReader: para la lectura de datos almacenados en ficheros XML.

ACCESO A BASE DE DATOS CON ADO.NET

7

Page 58: Módulo_8_Acceso a bases de datos con ADO

‘ Las importaciones comentadasImports SystemImports System.DataImports System.Data.SqlClient

Module Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentes‘ DataSource: indica el origen de los datos o proveedor de ‘ datos‘ Initial Catalog: es el nombre de la base de datos concreta ‘ contra la que quieres trabajar‘ Integrated security: es el tipo de acceso, en este caso, ‘ seguridad integrada de Windos, pero podría ser usuario y ‘ contraseña, aunque es bastante menos seguroDim connectionString As String = _

“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)

‘ Inicio del bloque Using comentado, con la creación de la‘ conexión SQLUsing connection As New SqlConnection(connectionString)

‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()

‘ Definimos la sentencia que vamos a aejecutarDim queryString As String = _

“SELECT TOP 10 [ContactID],[FirstName],[LastName]“ & _“, [Phone] FROM [Person].[Contact];”

‘ Asignamos la sentencia al comandocommand.CommandText = queryString

‘ Bolque Try para poder capturar las posibles excepciones

ACCESO A BASE DE DATOS CON ADO.NET

8

Page 59: Módulo_8_Acceso a bases de datos con ADO

‘ que se produzcan y controlarlas sin casque de programaTry

‘ Se abre la conexiónconnection.Open()

Console.WriteLine(“Conexión establecida, “ & _“leyendo los datos”)

‘ Carga el resultado de la ejecución del comando en ‘ un nuevo DataReaderDim dataReader As SqlDataReader =

command.ExecuteReader()

‘ Bucle de lectura hasta fin de registrosDo While dataReader.Read()

Console.WriteLine(vbTab & dataReader(0) & _vbTab & dataReader(1) & vbTab & _dataReader(2))

Loop

‘ Se cierra el DataReader para evitar error en el ‘ End UsingdataReader.Close()

Catch ex As Exception‘ Si se produce alguna excepción, lo notificamosConsole.WriteLine(ex.Message)

End TryEnd Using‘ Fin del bloque Using, aquí desaparece la conexión

‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)

‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

9

Page 60: Módulo_8_Acceso a bases de datos con ADO

Ahora el resultado de la ejecución de este código sería.

Como ves obtenemos lo mismo que antes desde la consola de SQL.

Lo único que no habías visto aún es la palabra clave vbTab, que aquí se usa en el Console.WriteLine(), y quesirve para insertar una tabulación, de esta forma los datos se presentan un poco alineados, aunque como hayalgún nombre largo, queda un poco descuajeringado, pero escribiendo en consola no se puede hacer muchomás.

ACCESO A BASE DE DATOS CON ADO.NET

10

Page 61: Módulo_8_Acceso a bases de datos con ADO

5.3 – Ejecución de procedimientos almacenados.

Los procedimientos almacenados, como ya vimos en el módulo de dicado a SQL, son grupos de sentencias SQL,almacenadas con nombre en la propia base de datos, que sirven para ejecutar tareas repetitivas o decodificación complicada, admitiendo parámetros de entrada y salida, además de los resultados que puedanproporcionar.

Es decir, si una tarea habitual en tu base de datos es la de añadir la información de un cliente, y estainformación se halla dispersa por un sinnúmero de tablas, relacionadas o no entre sí y con restricciones deexistencia cruzadas, la creación correcta de toda la información puede llegar a ser complicada. Por ello, eldiseñador de la base de datos establece cómo se ha de generar esta información, se desarrolla elcorrespondiente procedimiento almacenado, el cual recibirá como parámetros todos los datos que necesite,y efectuará la creación ordenada de los registros pertinentes, con sus dependencias y relaciones. Con lo quecada vez que se necesite crear un cliente, desde cualquier parte de los programas, sólo habrá que hacer unallamada al procedimiento almacenado y pasarle sus parámetros, sin tener que reinventar la rueda a cada vezy asegurándote de que no vayan a haber errores ni inconsistencias en la base de datos.

También es un sistema válido a la hora de recuperar información elaborada a partir de varias tablas, si elalgoritmo de búsqueda no es evidente o si implica varias tareas de creación de tablas temporales intermedias,es preferible tenerlo todo desarrollado y probado sólo una vez y guardado en la propia base de datos quetener que generar y probar el código cada vez que se necesite, sin estar seguro de que cada desarrolladorhaya tenido en cuenta todas las posibles variantes y de que el resultado ofrecido sea el correcto.

Otro uso habitual de los procedimientos almacenados es de mantenimiento de la propia base de datos, tantodesde el punto de vista del administrador como del programador. Siempre hay tareas de limpieza y depuraciónde datos que se pueden automatizar, con lo que se abunda en la seguridad e integridad. Encima, este tipode procedimientos de mantenimiento se pueden programar y la propia base de datos se encargaría delanzarlos en el momento de menor carga, registrando, opcionalmente, el resultado en un archivo de log. Conlo que el administrador sólo tendría que verificar en dicho log si todo ha funcionado correctamente.

Para el ejemplo vamos a utilizar un procedimiento almacenado ya existente en la base de datos“AdventureWorks”, que estamos utilizando de base de ejemplos, concretamente el “uspGetBillOfMaterials”.Te incluyo el código del mismo, no para que te lo estudies a fondo, ya que no tiene sentido al no conocer labase de datos, pero si para que veas el nivel de complejidad del código del mismo, tal y como hemoscomentado antes. ¿Te imaginas tener que codificar esto cada vez que necesitaras recuperar esta información?De esta forma, con pasarle los parámetros indicados, que son la identificación del producto y la fecha límitede vigencia de los sub-productos obtendremos la lista de componentes del mismo, y, de propina, un códigode retorno que nos indicará si todo ha funcionado correctamente o si se ha producido algún tipo de problema.

ACCESO A BASE DE DATOS CON ADO.NET

11

Page 62: Módulo_8_Acceso a bases de datos con ADO

/****** Object: StoredProcedure [dbo].[uspGetBillOfMaterials] Script Date: 11/21/200809:23:11 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE PROCEDURE [dbo].[uspGetBillOfMaterials]

@StartProductID [int],@CheckDate [datetime]

ASBEGIN

SET NOCOUNT ON;— Use recursive query to generate a multi-level Bill of Material (i.e. all level 1 — components of a level 0 assembly, all level 2 components of a level 1 assembly)— The CheckDate eliminates any components that are no longer used in the product on this

date.WITH [BOM_cte]([ProductAssemblyID], [ComponentID], [ComponentDesc], [PerAssemblyQty],

[StandardCost], [ListPrice], [BOMLevel], [RecursionLevel]) — CTE name and columnsAS (

SELECT b.[ProductAssemblyID], b.[ComponentID], p.[Name], b.[PerAssemblyQty],p.[StandardCost], p.[ListPrice], b.[BOMLevel], 0 — Get the initial list of components for the bikeassembly

FROM [Production].[BillOfMaterials] bINNER JOIN [Production].[Product] p ON b.[ComponentID] = p.[ProductID]

WHERE b.[ProductAssemblyID] = @StartProductID AND @CheckDate >= b.[StartDate] AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate)

UNION ALLSELECT b.[ProductAssemblyID], b.[ComponentID], p.[Name], b.[PerAssemblyQty],

p.[StandardCost], p.[ListPrice], b.[BOMLevel], [RecursionLevel] + 1 — Join recursive member toanchor

FROM [BOM_cte] cteINNER JOIN [Production].[BillOfMaterials] b ON b.[ProductAssemblyID] = cte.[ComponentID]INNER JOIN [Production].[Product] p

ACCESO A BASE DE DATOS CON ADO.NET

12

Page 63: Módulo_8_Acceso a bases de datos con ADO

ON b.[ComponentID] = p.[ProductID] WHERE @CheckDate >= b.[StartDate]

AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate))

— Outer select from the CTESELECT b.[ProductAssemblyID], b.[ComponentID], b.[ComponentDesc],

SUM(b.[PerAssemblyQty]) AS [TotalQuantity] , b.[StandardCost], b.[ListPrice], b.[BOMLevel],b.[RecursionLevel]

FROM [BOM_cte] bGROUP BY b.[ComponentID], b.[ComponentDesc], b.[ProductAssemblyID], b.[BOMLevel],

b.[RecursionLevel], b.[StandardCost], b.[ListPrice]ORDER BY b.[BOMLevel], b.[ProductAssemblyID], b.[ComponentID]OPTION (MAXRECURSION 25)

END;

Te lo he puesto tal cual, sin traducir ni nada ya que nos es objeto de este curso el que desarrolles este tipode procedimientos, pero creo que se entiende bastante bien.

Bueno pues, si ahora incorporamos la ejecución de este procedimiento almacenado en nuestro programa deconsola, ya sé que la salida no es muy espectacular, pero es mucho más sencillo de ver el código exclusivodel lanzamiento de esta forma.

Imports SystemImports System.DataImports System.Data.SqlClient

Module Module1Public Sub Main()

Dim connectionString As String = _“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Console.WriteLine(“Estableciendo la conexión”)

Using connection As New SqlConnection(connectionString)

ACCESO A BASE DE DATOS CON ADO.NET

13

Page 64: Módulo_8_Acceso a bases de datos con ADO

‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()

‘ Asignamos el tipo al comando y el procedimientpcommand.CommandType = CommandType.StoredProcedurecommand.CommandText = “dbo.uspGetBillOfMaterials”

‘ Asignamos valores a sus parámetroscommand.Parameters.Add(“@StartProductID”, & _

SqlDbType.Int).Value = 514command.Parameters.Add(“@CheckDate”, & _

SqlDbType.DateTime).Value = New DateTime(2008, 12, 31)

Tryconnection.Open()Console.WriteLine(“Conexión establecida, “ & _

“leyendo los datos”)Dim dataReader As SqlDataReader = & _

command.ExecuteReader()Do While dataReader.Read()

Console.WriteLine(vbTab & dataReader(0) & _vbTab & dataReader(1) & _vbTab & dataReader(2) & _vbTab & dataReader(3) & _vbTab & dataReader(4) & _vbTab & dataReader(5) & _vbTab & dataReader(6) & _vbTab & dataReader(7))

LoopdataReader.Close()

Catch ex As ExceptionConsole.WriteLine(ex.Message)

End TryEnd Using

Console.WriteLine(“Conexión cerrada”)Console.ReadLine()

End SubEnd Module

ACCESO A BASE DE DATOS CON ADO.NET

14

Page 65: Módulo_8_Acceso a bases de datos con ADO

Como ves, no es para tanto, se define el Command casi de la misma forma, en lugar de asignar la sentenciaSQL a su texto, se le asigna el nombre del procedimiento almacenado, tras decirle, en su tipo, que esprocedimiento almacenado. Quizás lo más complicado sea la asignación de parámetros. Una peculiaridad esque debes saber cuáles son los parámetros y el tipo de dato de los mismos para asignarlos, pero creo que esbastante normal, si vas a usar una herramienta, debes saber por qué lado la has de coger y cómo se utiliza¿no?

Por lo demás su comportamiento, a la hora de asignarlo al DataReader y operar con éste es idéntico alejemplo anterior.

Y al pulsar F5 para ejecutar nuestro programa obtenemos lo siguiente:

ACCESO A BASE DE DATOS CON ADO.NET

15

Page 66: Módulo_8_Acceso a bases de datos con ADO

5.4 - Transacciones.

Bueno, vamos a por el último apartado de esta unidad didáctica, si te parece, es el referente a lastransacciones.

Ya las habíamos comentado por encima, pero ahora nos vamos a meter un poco más a fondo con ellas.

Una transacción es el nombre que se le da a un paquete de operaciones consecutivas efectuadas contra unabase de datos para asegurar la integridad de los mismos.

Me explico, y nada mejor que un ejemplo, imagínate cualquier empresa, con sus clientes, cartera de pedidosy contabilidad. Cuando llega final de mes hay que lanzar la facturación. Esto implica que habrá que acumularlos pedidos ya entregados pendientes de facturar, elaborar la correspondiente factura, generar el registrode la misma en la contabilidad y actualizar el saldo pendiente del cliente. ¿Hasta aquí bien, no? Nada nuevobajo el sol. EL problema puede ser que en medio de estas operaciones ocurra cualquier tipo de problema conlos ordenadores, con lo que, si efectuáramos las operaciones de forma individual y consecutiva, nospodríamos quedar con los pedidos marcados como facturados y la factura sin registrar, o ésta registrada perosin generar los asientos contables o …etc. Las posibilidades de casque son infinitas, como los caminos delSeñor.

La única forma de garantizar que todo funcione correctamente y no tengamos un sistema con inconsistenciade datos es el utilizar transacciones.

En este caso, por cada cliente tratado, iniciaríamos una transacción, con lo que todas las operaciones queefectuáramos, dentro de dicha transacción, contra la base de datos se irían registrando en un archivoespecial. Al finalizar el paquete completo, le diríamos a la transacción que hiciera un Commit, si todo ha idobien o un Rollback en caso contrario.

El Commit haría que se marcarán como efectuadas y correctas todas las modificaciones aportadas a la basede datos, moviendo el puntero de movimientos completados de ese archivo especial a justo después delúltimo de los registros de dicha transacción.

En cambio el Rollback, cogería e iría deshaciendo cada uno de los registros de la transacción hasta encontrarel último punto de Commit correcto, dejando la base de datos en la situación estable con la que empezó latransacción.

¿Está claro?

Para poder utilizar transacciones hay que importar el espacio de nombres System.Transactions, para disponerde los objetos asociados a DbTransaction, como código genérico y luego utilizar las específicas del proveedorde datos que estemos utilizando.

Y la forma de utilizarlas tiene un varias opciones, como siempre, una de ellas, la más recomendada,es similar al uso que hemos hecho de la conexión en el ejemplo anterior, es decir crear la transacciónen un Using, con lo cual todo el código relacionado con la misma iría dentro del bloque, si añadimos

ACCESO A BASE DE DATOS CON ADO.NET

16

Page 67: Módulo_8_Acceso a bases de datos con ADO

un bloque Try, podremos codificar el Rollback en el/los Catch asociado/s al mismo y asegurarnos que todoestá controlado.

Otra, que se recomienda cuando hay muchas tablas implicadas, es el uso dentro de un procedimientoalmacenado, utilizando los comandos Transact SQL: BEGIN TRANSACTION, COMMIT TRANSACTION y ROLLBACKTRANSACTION.

La otra forma de utilizar transacciones en nuestro código es mediante el uso de los objetos Connection yCommand, para variar.

Iniciaríamos la transacción con el método BeginTransaction del objeto Connection del proveedor de datos queestemos utilizando y la finalizaríamos con los métodos Commit o Rollback del mismo objeto.

Luego el objeto de tipo Transaction obtenido con el BeginTransaction se asigna a la propiedad Transactiondel Command y después ya se pueden ir ejecutando distintas sentencias con el Command, debiendo ejecutaruno de los dos métodos de cierre para finalizar las operaciones.

Como ya hemos comentado, lo adecuado es meter las operaciones de la transacción en un bloque Try, ya quelas posibilidades de problemas en algún punto son muy altas y añadir, por lo tanto, el correspondienteRollback en el Catch asociado, en todos si hay más de uno. Pero este Rollback también tiene que ir dentrode su propio bloque Try, ya que siempre es posible que con el error que ha hecho saltar el Catch, el propiogestor de la base de datos haya efectuado su propio Rollback o que la conexión se haya perdido, y un segundoRollback resultaría en un error.

Vamos a ver esto en un ejemplo, a ver si queda más claro.

Situación inicial de los datos, no hay provincia para España.

ACCESO A BASE DE DATOS CON ADO.NET

17

Page 68: Módulo_8_Acceso a bases de datos con ADO

Generamos pues el código para insertar un par de provincias, con una transacción para asegurar que seinserten ambas.

Imports SystemImports System.DataImports System.Data.SqlClientImports System.TransactionsModule Module1

Public Sub Main()‘ Aquí definimos la cadena de conexión‘ como puedes ver tiene varios componentesDim connectionString As String = _

“Data Source=LG-TONY\SQLEXPRESS2008;” & _“Initial Catalog=AdventureWorks;” & _“Integrated Security=SSPI;”

Using connection As New SqlConnection(connectionString)connection.Open()‘ Iniciamos una transacción contra el objeto ConnectionDim sqlTran As SqlTransaction = _

connection.BeginTransaction()Console.WriteLine(“Iniciada la transacción”)‘ Definimos el comando a utilizarDim command As SqlCommand = connection.CreateCommand()command.Transaction = sqlTranTry

‘ Insertamos un par de registros‘ Definimos la sentencia SQL a ejecutar‘ primero la parte fija

Dim sql1 As String = “INSERT INTO Person.StateProvince (StateProvinceCode,CountryRegionCode, IsOnlyStateProvinceFlag, Name, TerritoryID) “

‘ Aquí la parte variable por registroDim sql2 As Stringsql2 = “VALUES(‘VI ‘,’ES ‘, 0, ‘Alava’, 7)“Dim sql As String = sql1 & sql2‘ La asignamos al comandocommand.CommandText = sqlcommand.ExecuteNonQuery()

ACCESO A BASE DE DATOS CON ADO.NET

18

Page 69: Módulo_8_Acceso a bases de datos con ADO

‘ Segundo registrosql2 = “VALUES(‘AB’,’ES’, 0, ‘Albacete’, 7)“sql = sql1 & sql2‘ La asignamos al comandocommand.CommandText = sqlcommand.ExecuteNonQuery()‘ Commit de la transacciónsqlTran.Commit()Console.WriteLine(“Se han añadido los registros.”)

Catch ex As ExceptionConsole.WriteLine(ex.Message)Try

‘ Intenta hacer el Rollback a la transacción.sqlTran.Rollback()

Catch exRollback As Exception‘ Si falla, muestra el errorConsole.WriteLine(exRollback.Message)

End TryEnd Try

End Using‘ Aviso al usuarioConsole.WriteLine(“Conexión cerrada”)‘ Como siempre, para que puedas leer lo escritoConsole.ReadLine()

End SubEnd Module

Creo que habla por si mismo ¿no?

Está claro que el tema de la sentencia de inserción se podría haber solucionado de una forma más elegante,por ejemplo con parámetros, que habría sido lo correcto, pero no te quería complicar las cosas.

Siempre hay que tener mucho cuidado con el tema de las comillas, al SQL sólo le gustan las comillas simples,y éstas, dentro de las dobles, no requieren duplicidad, te lo digo porque yo siempre pico y me toca corregir.

ACCESO A BASE DE DATOS CON ADO.NET

19

Page 70: Módulo_8_Acceso a bases de datos con ADO

Bueno, si pulsamos F5.

Y si comprobamos en la base de datos:

ACCESO A BASE DE DATOS CON ADO.NET

20

Page 71: Módulo_8_Acceso a bases de datos con ADO

EN RESUMEN

Hemos visto la utilización de los objetos Connection, Command, DataReader para el acceso adatos mediante ADO.NET de forma conectada.

También hemos visto cómo se pueden utilizar procedimientos almacenados con la misma técnica.

Finalmente, hemos visto cómo utilizar transacciones desde nuestro código, mediante el objetoTransaction de la conexión y los métodos BeginTransaction, Commit y Rollback de la misma.

ACCESO A BASE DE DATOS CON ADO.NET

21

Page 72: Módulo_8_Acceso a bases de datos con ADO

VINCULACIÓN DECONTROLES

WINDOWS A DATOS

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 73: Módulo_8_Acceso a bases de datos con ADO

ÍNDICE

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3

2. Vinculación de controles tipo ListControl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5

3. El control DataGridView. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7

4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16

Page 74: Módulo_8_Acceso a bases de datos con ADO

3

1. Introducción

Para el el acceso a datos desde controles en formularios Windows,necesitarás tener muy claro el esquema de la o las bases de datos de las quehayas de recuperar los datos, así como las dependencias funcionales entre lasdiferentes tablas, para poder planificar adecuadamente los DataSets y laforma de trabajar con ellos.

Para empezar, dispones de una nueva herramienta, el Explorador de Servidores.

Te permite visualizar, de modo gráfico, la lista de todos los servidores de bases de datos a los que tienesacceso y, dentro de cada uno de ellos, cada una de las bases de datos. Un poco en la forma en que lo hacela consola de administración de SQL Server.

Desde ese interfaz puedes, fácilmente, agregar conexiones de datos a las soluciones, así como diseñar elmodelo de datos que se va a necesitar. Lo que implica los DataAdapters, los DataSets e incluso todos y cadauno de los DataTable, con todas las relaciones y restricciones existentes en la base de datos de origen.

Formulario BindingSource

También existe la posibilidad de agregar un acceso a origen de datos en elformulario (BindingSource), con lo que aparecerá un asistente para enlazara una conexión dada o crear una nueva, quedando disponible para serenlazado desde los controles.

Pero no se limita a lo que se pueda extraer de una base de datos, ya quedesde los formularios Windows se puede definir el acceso a datos de todotipo de orígenes, como puedan ser ficheros XML u otros controles o datosgenerados en tiempo de ejecución.

Enlace de datos

Una funcionalidad agregada en esta última versión de .NET Framework, y por ende del IDE de Visual Studio,es la posibilidad de enlazar a datos algo más que las propiedades de texto o relleno de los controles.

Page 75: Módulo_8_Acceso a bases de datos con ADO

4

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

Ahora casi todas las propiedades de los controles son enlazables a datos, con lo que los colores de fondo oprimer plano, el tamaño de los controles, las imágenes contenidas en controles gráficos,… etc, se puedenenlazar con un origen de datos. De esta forma se obtienen formularios realmente interactivos y ligadosdinámicamente a la información.

Esto permite generar el típico “Cuadro de Mando” para la dirección directamente en pantalla, con lasposibilidades de Drill-Down y Drill-Up que se derivan de ello, además de lo efectistas y aparentes que resultaneste tipo de aplicaciones.

Controles para formularios de Windows

Dentro de los controles para formularios de Windows, para presentación pura de datos más habituales,podemos encontrar:

ListControlSirve para presentar listas de datos en pantalla y que el usuario pueda realizar selecciones sobre ellos. Deesta clase, que no se puede utilizar directamente, es de la que heredan los controles ComboBox y ListBox.

DataGridViewSe utiliza para la presentación de la información en un formato tabular, similar a las hojas de cálculo tipoExcel.

Page 76: Módulo_8_Acceso a bases de datos con ADO

2. Vinculación de controles tipo ListControl

Controles de tipo ListControl

Los controles de tipo ListControl son los utilizados para presentar una lista de datos al usuario para quepueda realizar una selección sobre ellos. De esta clase, no instanciable, derivan los controles:

- ComboBox- ListBox

De esta clase, los miembros más importantes, en lo que a datos se refiere son:

DataSourceOrigen de los datos del control

SelectedValueValor atómico seleccionado

DisplayMemberColumna de datos que se mostrará en el control

ValueMemberColumna de datos que contiene el dato a almacenar del registro seleccionado

ListBox

El control ListBox además de los miembros heredados, ya enunciados, dispone de los siguientes de formaparticular:

MultiColumnIndica si se mostrará más de una columna con los datos en el control.

SelectionModeIndica el tipo de selección que se puede realizar.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

5

Page 77: Módulo_8_Acceso a bases de datos con ADO

También dispone de un surtido de miembros para controlar el aspecto visual del control, de otros para elllenado del control con datos no enlazados y, finalmente, para efectuar búsquedas en la lista, mediantecódigo.

Tres colecciones importantes para manejar los datos contenidos:

ItemsTodos los elementos contenidos en el control.

SelectionItemsLos elementos seleccionados.

SelectedIndicesLos índices de los elementos seleccionados.

ComboBox

El control ComboBox es el típico cuadro de edición/selección de Windows, presenta un cuadro de texto paraedición con la posibilidad de desplegar un ListBox bajo él con el que seleccionar el valor único con el querellenar el cuadro de texto, el cuál puede no ser editable por el usuario, estando limitado a seleccionar dela lista.

El comportamiento de presentación y edición del cuadro de texto se controla con la propiedadDropDownStyle.

Dispone de miembros para añadir registros al control y para realizar búsquedas dentro de la lista deelementos.

En cambio, en lugar de las colecciones de las que dispone el ListBox,este control, al ser de selección única, tiene los valores individualesSelectedItem y SelectedIndex, para contener el valor seleccionado dela lista.

De esta clase hereda la DataGridViewComboBoxEditingControl

Se utiliza dentro de un DataGridView para insertar un ComboxBox paraalguna celda.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

6

Page 78: Módulo_8_Acceso a bases de datos con ADO

3. El control DataGridView.

Enlaces de controles

Como ya hemos comentado la clase DataGridView se utiliza para lapresentación de datos de forma tabular, es decir en cuadrículas de filas ycolumnas.

Pueden ser de simple presentación o de edición de los datos, permitiendoinsertar, modificar o eliminar registros.

Se dispone de un amplio surtido de miembros para controlar el aspecto gráfico del control.

Un control DataGridView puede tener su enlace a datos a otro DataGridView. Ya hemos comentado que elenlace a datos permite enlazar con otros controles. Pero en este caso es especialmente frecuente ya quepermite la típica presentación de cabeceras y detalles, tan habitual en los programas empresariales.

También se puede presentar un DataGridView vacío y/o no enlazado a ningún origen de datos, con el cual sepueden generar los datos en local y disponer posteriormente de ellos cuando se necesiten.

Acceso concreto a los datos contenidos en el control

Para el acceso concreto a los datos contenidos en el control, existen lossiguientes miembros:

Columns y RowsPara acceder a las columnas y filas de datos, respectivamente.

Items y Cells Para acceder a celdas concretas del control.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

7

Page 79: Módulo_8_Acceso a bases de datos con ADO

DataSource y DataMember Para enlazar con un origen de datos y así poder indicar al control de dónde ha de recuperar la información.

Cuando este control se enlaza a un origen de datos, normalmente, genera de forma automática las columnasen función de las que tenga el origen de datos, lo cual no impide que se añadan nuevas columnas por nuestraparte. Columnas para mostrar botones de acción o controles de selección o datos calculados, para lo cualviene muy bien la propiedad DataColumn.Expression, ya que nos permite calcular el valor de una celda apartir del de otras con una expresión aritmética compleja.

Control DataGridView

En el modo enlazado a datos, el control DataGridView es de mucha utilidad ya que la mayoría de lafuncionalidad requerida para recuperar, presentar o actualizar los datos desde y hacia el origen de datos estáimplementada por el propio control, con lo cual podemos dedicarnos a otros temas sin tener que entrar enla tediosa codificación de la navegación y actualización de la información.

Incluso si el control es añadido al formulario en tiempo de ejecución mediante código, si se inicializanadecuadamente las correspondientes propiedades, el sistema implementará toda esta funcionalidad pornosotros.

Ejemplos de los tipos de enlaces

A continuación se muestra un ejemplo de formulario con los tres tipos de controles comentados, enlazadosa datos.

En este caso, lo primero es ir al explorador de servidores y añadir una nueva conexión, tal y como se muestraa continuación:

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

8

Page 80: Módulo_8_Acceso a bases de datos con ADO

Una vez aceptado el cuadro de diálogo anterior, dispondremos de una vista del contenido de la base dedatos:

Ahora nos vamos al diseño del formulario y añadimos un control ListBox, un ComboBox y un DataGridView,tal y como se muestra a continuación.

Evidentemente, en este punto, no tenemos prácticamente nada, excepto la propiedad DropDownStyle delComboBox cambiada a Simple, para ver la lista de ítems.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

9

Page 81: Módulo_8_Acceso a bases de datos con ADO

Después añadimos un BindingSource y lo enlazamos a la conexión antes definida mediante la creación de unnuevo DataSource para el proyecto, generado mediante el asistente, según se muestra:

1

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

10

Page 82: Módulo_8_Acceso a bases de datos con ADO

2

3

4

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

11

Page 83: Módulo_8_Acceso a bases de datos con ADO

5

Así queda el formulario, una vez completado el asistente de creación del nuevo DataSource.

Te habrás fijado en la franja inferior donde van apareciendo aquellos objetos que se han creado al añadir uncontrol al formulario, pero que no tienen representación gráfica. Es bastante más cómodo que el sistemaanterior de colocar en el propio formulario una representación gráfica visible sólo en diseño.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

12

Page 84: Módulo_8_Acceso a bases de datos con ADO

Ejemplos de los tipos de enlaces – Asignación de origen de datos

Asignación al ListBox.

Asignación al ComboBox

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

13

Page 85: Módulo_8_Acceso a bases de datos con ADO

Asignación al DataGridView

Lo único que hemos hecho ha sido indicar el valor BibdingSource1 en la propiedad DataSource. Si te fijasdetrás, el control ya tiene las columnas de la tabla preparadas.

Ejemplos de los tipos de enlaces - Resultado

Éste es el resultado:

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

14

Page 86: Módulo_8_Acceso a bases de datos con ADO

La utilización del asistente es un gran avance, y que sin necesidad de teclear ningún código se tiene laoperativa requerida disponible.

Evidentemente, si queremos agregar la funcionalidad de añadir datos en alguno de los controles, seránecesario implementarlo y codificar todo lo que conlleva detrás.

Al estar todos los controles ligados al mismo miembro de datos del origen de datos, al seleccionar uno encualquiera de los controles, se posicionan los otros en el mismo registro.

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

15

Page 87: Módulo_8_Acceso a bases de datos con ADO

4. Resumen

Has llegado al final de esta lección de formación que denominamos “Vinculación de controles Windows adatos”.En esta lección hemos estudiado los siguientes contenidos:

VINCULACIÓN DE CONTROLES WINDOWS A DATOS

16

Page 88: Módulo_8_Acceso a bases de datos con ADO

ACCESO A BASE DEDATOS CON

ADO.NET

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 89: Módulo_8_Acceso a bases de datos con ADO

ADO. NET, ejemplos de acceso a las bases de datos

Existen multitud de tecnologías para almacenar y recuperar datos a las que se les ha dado una variedad denombres como DAO, RDO, ODBC, OLE DB y ADO.

Es difícil elegir entre tanta variedad para determinar las herramientas indicadas para un determinadotrabajo. Cosas a tener en cuenta son la compatibilidad, la calidad general, robustez, frecuencia deactualización de los productos para solucionar problemas y mejorar el rendimiento. Querremos que unasolución de una compañía dure lo suficiente para proporcionar la compatibilidad que necesita nuestraaplicación. Esto nos lo puede facilitar de sobra ADO.NET.

Estos datos pueden proceder de fuentes diferentes como archivos de valores separados por comas, XML,email, hojas de cálculo o formatos binarios o de texto. Por lo general obtendremos la información de basesde datos como Microsoft Access, SQL Server, Visual Fox Pro, Oracle, DB2, Sybase o Informix.

ADO.NET existe para solventar problemas como compartición de datos entre clientes, recibir pedidos online,recuperar informes de mercado, etc.

ACCESO A BASE DE DATOS CON ADO.NET

2

Page 90: Módulo_8_Acceso a bases de datos con ADO

TECNOLOGIAS DE ACCESO A DATOS

Ahora veremos de forma breve la evolución de las tecnologías de acceso a datos. Con la nueva versión sesolucionan algunos de los problemas de los productos anteriores y se mejoran herramientas disponibles paralos programadores de bases de datos:

ODBC. O Conectividad para bases de datos abiertas. El proveedor de datos con más éxito hasta la fecha. Escompatible con más lenguajes de programación que ninguna otra tecnología de acceso a datos.

Microsoft fue la primera empresa en comercializar esta especificación.

Con ODBC 1.0. Desde entonces, muchos proveedores han incluido en sus productos compatibilidad conMicrosoft ODBC y, en la actualidad, existen más de 170 controladores ODBC disponibles.

ODBC proporciona una serie de funciones API que puede utilizar para acceder a una amplia variedad defuentes de datos. Por medio de un administrador de controladores, se traduce la instrucción solicitada a lasintaxis nativa y, tras ello, se devuelven los resultados a la aplicación. Este mecanismo ofrece al programadorun conjunto de instrucciones para diferentes sistemas, independientemente de la plataforma, proveedor,base de datos y lenguaje que se emplee. Sin embargo, el funcionamiento del API ODBC es complejo y pocointuitivo y algunos de los controladores presentan inconsistencias que requieren el diseño de códigospersonalizados para solucionarlas.

DAO. Los objetos de acceso a datos, que aparecieron en Access 1.0 en 1992, constituyen una tecnologíadiseñada en torno al motor JET, capaz de acceder a bases de datos de Microsoft Access, a bases de datos ISAMexternas incluyendo, Btrieve, dBase, Paradox, FoxPro y orígenes de datos ODBC. Visual Basic 3.0 ofrececompatibilidad con DAO y con el motor de bases de datos Microsoft JET y, durante un tiempo, fue el métodomás utilizado para comunicarse con fuentes de datos Access e ISAM.

RDO. Objetos de datos remotos; apareció con la versión de 32 bits de VB4 en 1995, específicamente paraacceder a fuentes de datos ODBC remotas, como Microsoft SQL Server y Oracle, pero sin la complicada sintaxisdel API ODBC. El modelo de objetos RDO se basaba en DAO e incluía algunas de las mejores característicasde su interfaz y de sus funciones, sin la necesidad de utilizar el motor JET. Esto condujo a un rendimientomejorado con respecto a DAO para bases de datos que no fueran de Access. RDO disponía de un cursorinteligente, lo que aumentaba la velocidad de procesamiento de los datos. En comparación con DAO,procesaba mejor las consultas y los conjuntos de resultados, era más rápido y requería una menor sobrecarga.Muchas de estas ventajas de rendimiento se derivan del hecho de que RDO se comunica directamente conel API ODBC sin tener que pasar por otros niveles. Sin embargo, no tuvo mucho éxito debido a la apariciónde tecnologías mejoras.

ACCESO A BASE DE DATOS CON ADO.NET

3

Page 91: Módulo_8_Acceso a bases de datos con ADO

ODBCDirect. Apareció en 1997 con Visual Basic 5.0 como alternativa a DAO, que podemos situar entre elmotor JET y RDO. Proporcionaba acceso directo a fuentes de datos ODBC, sobrepasando al motor MicrosoftJET. De forma interna, utiliza el motor RDO y, de hecho es muy similar a RDO pero con nombres de objetosDAO. En comparación con DAO, ODBCDirect ofrece un mejor rendimiento, mejores recursos, un mejor accesoa las funciones del lado servidor y mejores métodos de actualización y consulta. El inconveniente es que nopuede acceder a fuentes que no sean ODBC.

OLE DB. Vinculación e incrustación de objetos para bases de datos. El API de Microsoft para el acceso universala datos permite la comunicación con fuentes relacionales y no relacionales incluyendo datos legados o desistemas centrales (mainframe) que utilicen un Modelo de objetos de componentes (COM). Apareció en 1996y proporciona todas las prestaciones de ODBC aunque divididas en dos componentes: consumidores yproveedores. Los componentes de consumidor utilizan los datos, mientras que los de proveedores hablancon los datos y muestran una interfaz a los consumidores. Puede procesar distintos tipos de fuentes de datosno relacionales como correo electrónico, sistemas de archivos, gráficos y muchas otras fuentes de datospersonalizadas. Actualmente, es el centro de la tecnología de bases de datos de Microsoft.

ADO. Objetos de datos ActiveX. Es un envoltorio de OLE DB comercializado por primera vez en 1996 paraocultar la complicada sintaxis de OLE DB. Cuenta con características similares a DAO y RDO y, aunque se hadiseñado para un tráfico de red mínimo, su rendimiento es adecuado y resulta sencillo de aprender. ADOcuenta con todas las prestaciones de OLE DB, lo que significa que podemos acceder a fuentes de datos dedistintos proveedores. El diseño de este modelo se basa en una arquitectura con conexión, aunque permitela configuración sin conexión, lo que implica que los datos se almacenan en memoria sin una conexión activaa la base de datos, para que el trabajo se pueda realizar en los datos sin depender de una red que puede serlenta o, en ocasiones, no encontrarse disponible. Los componentes u objetos de un sistema deben estarconectados entre sí en posición a casos en los que los componentes pueden funcionar independientementey sólo comunicarse entre sí cuando sea necesario.

ADO.NET. Apareció en el 2000 y es la última tecnología ADO y RDS de Microsoft. Como se construye en XML,el estándar de la industria que pretende cambiar la forma en la que trabajamos con datos, se puede controlarpor cualquier aplicación que pueda leer dicho estándar independientemente de la plataforma (Windows,Linux o Unix) o del lenguaje (C++, VB, Delphi u otro).

ADO.NET

ADO.NET proporciona conectividad para bases de datos entre sistemas relacionales o no relacionales a travésde un conjunto de componentes común.

ACCESO A BASE DE DATOS CON ADO.NET

4

Page 92: Módulo_8_Acceso a bases de datos con ADO

También permite el acceso a datos sin conexión. Tradicionalmente, las aplicaciones cliente-servidormantienen, durante su ejecución, una conexión abierta con la base de datos u ofrecen su propio método paraalmacenar localmente en caché los datos, lo que resulta poco práctico por distintas razones:

Las conexiones abiertas a bases de datos consumen valiosos recursos del sistema. En la mayoría de los casos,las bases de datos solamente pueden mantener un número determinado de conexiones abiertas simultáneasy la sobrecarga de un elevado número de conexiones puede mermar el rendimiento general de la aplicación.Sin embargo, en muchos casos, se puede requerir una conexión constante y puede que no resulte adecuadoni práctico cerrar la conexión. Resulta muy complicado escalar aplicaciones que requieren una conexión abierta a la base de datos, por loque una aplicación que funcione aceptablemente con 100 usuarios puede que no lo haga con 1000. Un modelo basado en datos con conexión puede dificultar el intercambio de datos entre los límites de laaplicación y de la organización. Si dos componentes necesitan compartir los mismos datos, ambos deberánconectarse a la misma fuente de datos o se debe implementar una forma fiable de pasar los datos entre loscomponentes.

Por todas estas razones, se diseñó ADO.NET para arquitecturas sin conexión. Los datos e leen en uncomponente (un objeto para se más preciso) denominado DataSet, que actúa como almacén temporal de losdatos. El DataSet almacena los datos aunque se rompa la conexión con la fuente de datos y es efectivosiempre que se encuentre en su alcance. La aplicación puede manipular los datos del DataSet sin conexiónantes de volver a conectar con el almacén de datos para actualizarlo con los cambios. Los cambios seefectúan de forma optimista. Al volver a establecer la conexión para una actualización, las versionesoriginales de los datos utilizados para completar el DataSet se comparan con los datos que en ese momentocontiene el servidor. Si alguien ha modificado la información mientras tanto, se genera un error y se rechazala operación.

El DataSet utiliza XML para transferir los datos. Se trata de un lenguaje que marca los datos con etiquetaspersonalizables de forma estándar y que permite a organizaciones y aplicaciones independientes comprenderlos datos de cada una.

EL OBJETO DATASET

Se trata de una representación de datos en memoria independiente de la fuente de datos original. Es unobjeto de datos sin conexión y una vez completado con datos actuará independientemente de otro objetosin necesidad de conectarse a la base de datos.

ACCESO A BASE DE DATOS CON ADO.NET

5

Page 93: Módulo_8_Acceso a bases de datos con ADO

Los métodos y objetos a usar son parecidos a los del modelo de bases de datos relacionales. El DATASET estacompuesto por cinco tipos de objetos diferentes: colecciones de tablas, filas, columnas, restricciones yrelaciones como una base de datos. Un dataset puede o no contener tablas.

Dim myDataSet As DataSet = New DataSet( )oDim myDataSet As DataSet = New DataSet (“MyCustomerDataSet”)

Podremos obtener una instancia de un DATASET con la palabra clave New del objeto DATASET. Se le pasa elnombre del DATASET como parámetro. De modo contrario se usara el nombre predeterminado NewDataSet.Los DATASET son contenedores de información a los que accederemos cuando queramos.

EL OBJETO DATATABLE

Un DATASET tiene una colección de tablas de forma de DataTableCollection. El DATASET almacena unareferencia a ese objeto en su propiedad Tables. Cada tabla individual residente en memoria se denominaDataTable y puede haber varias o ninguna dentro de la colección. Las DataTables tienen filas de datos y cadauna de estas filas esta compuesta por columnas. Crearemos un objeto DataTable de la siguiente manera:

Dim myCustomerTable As DataTable = New DataTable( )oDim myCustomerTable As DataTable= New DataTable (“CustomersTable”)

La primera línea crea una nueva tabla sin ningún parámetro de nombre de tabla, por lo que el nombre de latabla permanecerá en blanco. La segunda línea crea una nueva tabla pero especifica un nuevo nombre detabla, en este caso CustomersTable. Podemos añadir una nueva tabla a un DataSet mediante el método Add de la propiedad Tables del DataSet:

Dim myDataSet As DataSet = New DataSet (“MyDataSet”)Dim myCustomerTable As DataTable = myDataSet.Tables.Add(“CustomersTable”)

Aquí añadimos una nueva tabla denominada CustomersTable al nuevo DataSet MyDataSet. También podemosañadir una tabla existente a un DataSet pasándole el objeto DataTable:

‘creamos un nuevo DataSet denominado MyDataSet.Dim myDataSet As DataSet = New DataSet (“MyDataSet”)

‘creamos una nueva tabla denominada MyDataTable.Dim myDataTable As DataTable = New DataTable (“CustomersTable”)

‘añadimos la tabla existente al DataSet.Dim myCustomersTable As DataTable = myDataSet.Tables.Add (myDataTable)

ACCESO A BASE DE DATOS CON ADO.NET

6

Page 94: Módulo_8_Acceso a bases de datos con ADO

Si no le especificamos el nombre de la tabla al añadir una nueva tabla al DataSet se le asignara el nombrepredeterminado TableN, donde N empieza en el numero 1 y se incrementa sucesivamente. Se aconsejanombrar las tablas de forma personal con nombres descriptivos. Se produce una excepción si se intentaañadir una tabla con un nombre ya existente en el DATASET. Podemos hacer referencia a una tabla por sunombre en el DATASET:

Dim myCustomerTable As DataTable = myDataSet.Tables (“CustomersTable”)

Vemos que ADO.NET es sensible a mayúsculas y minúsculas por lo q podremos definir dos tablas con el mismonombre pero distinto tamaño de letra. También podemos hacer referencia a una determinada tabla por elíndice en el DATASET.

Dim myCustomerTable As DataTable = myDataSet.Tables (0)

En las tablas del DataSet, la referencia por índice siempre empieza en el valor cero, por lo que este códigohace referencia a la primera tabla. Eliminaremos una tabla de un DataSet de la siguiente manera:

myDataSet.Tables.Remove (“CustomerTable”)oDim myCustomerTable As DataTable = myDataSet.Tables(“CustomerTable”)

myDataSet.Tables.Remove (myCustomerTable)

Así eliminamos la tabla CustomerTable. Se puede eliminar también una tabla pasando un objeto DataTable.La propiedad DataSet.Table tiene una referencia al objeto DataTableCollection que enumera las tablas.Podemos mantener esta colección si invocamos los métodos de objeto, como son Add y Remove. No sepueden eliminar por índice.

EL OBJETO DATACOLUMN

Antes de añadir filas es necesario definir el esquema. Normalmente se crea al crear un nuevo DATASET. Esteesquema define la estructura de la tabla. Cuando se crea por primera vez la tabla no tenemos ningúnesquema asociado hasta que se añaden columnas a ella. El objeto DataColumn representa una columna y esla clave para crear un esquema de DataTables. Al añadir columnas a una colección DataColumn se genera elesquema. En nuestra tabla tenemos una colección de columnas llamada DataColumnCollection y cada unode los elementos de la colección hace referencia a un nombre de columna de nuestra tabla. Accederemos a

ACCESO A BASE DE DATOS CON ADO.NET

7

Page 95: Módulo_8_Acceso a bases de datos con ADO

esos nombres de columnas haciendo referencia a la propiedad Columns del objeto DataTable. Para ver losnombres de la columna de DataColumnCollections tendremos que recorrer la colección de esta forma:

Dim myDataColumn As DataColumn

For Each myDataColumn In myCustomerTable.ColumnsConsole.WriteLine ( myDataColumn.ColumnName )

Next

Si tenemos una tabla con los nombres de columna Dirección, Ciudad, Provincia y CP, tendremos unaDataColumnCollection correspondiente a dichos nombres. Para hacer referencia a los nombres de columnasharemos referencia a la colección, como haríamos con cualquier otro objeto de una colección. Para hacerreferencia a una columna por nombre usamos la propiedad Columns del DataTable especificando el nombrede columna:

Dim myColumn As DataColumnmyColumn = myCustomerTable.Columns (“Direccion”)

También podemos hacer referencia por su índice:

Dim myColumn As DataColumnmyColumn = myCustomerTable.Columns (0)

Si queremos añadir una nueva columna a una tabla usamos el método Add de la propiedad Columns de latabla:

Dim myDataSet As DataSet = New DataSet( )

‘Añadimos una nueva tablamyDataSet.Tables.Add (“CustomersTable”)

‘Hacemos referencia a la nueva tablaDim myCustomerTable As DataTable = myDataSet.Tables (“CustomerTable”)

‘Añadimos una columna de direcciones a la nueva tabla.myCustomerTable.Columns.Add (“Address”,Type.GetType(“String”))

ACCESO A BASE DE DATOS CON ADO.NET

8

Page 96: Módulo_8_Acceso a bases de datos con ADO

Debemos especificar un nombre de columna y su tipo como parámetro del método Add. Puede ser cualquiertipo de .NET Framework ya que no estamos vinculados a ningún tipo de fuente de datos. Para este casocreamos una columna denominada Address y especificamos el tipo de datos String. Igual que con el objetotabla, si no especificamos un nombre de columna al añadir una nueva columna a la tabla, se asignará elnombre predeterminado Columna, donde N se incrementa en una unidad y genera nombres predeterminadosempezando por Column1.

EL OBJETO DATAROW

Los objetos DataRow y DataColumn forman el DataTable. Mediante las propiedades y métodos de estosobjetos, podemos ver, actualizar, insertar y eliminar información de una tabla. DataRow representa los datosde las tablas y está dentro del objeto DataRowCollection. Igual que con DataColumnCollection podemosacceder a diferentes elementos de una colección por medio de los métodos de colección estándar. Las filas son representadas por una colección de tabla denominada Rows por lo que, para acceder a la primerafila de una tabla, podríamos utilizar el siguiente código, utilizando un índice de base cero:

myCustomerTable. Rows (0)

Si queremos ver todos los elementos de la colección DataRow iteramos la colección así:

CONST ADDRESS_COLUMN As Integer = 2Dim myDataRow as DataRowFor Each myDataRow In myCustomerTable.Rows

Console.WriteLine (myDataRow(ADDRESS_COLUMN).ToString( ))Console.WriteLine (myDataRow(“Address”).ToString( ))

Next

Así se mostrarán los contenidos del tercer índice de columna de la tabla usando la constanteADDRESS_COLUMN. Se trata de otra colección de base cero por lo que la primera fila es cero, la segunda uno,y así sucesivamente. Necesitaremos utilizar un número que representa el índice del valor de la columna a laque queremos acceder pero también podemos utilizar el nombre de la columna o un objeto de columna.Debemos tener en cuenta que como no tenemos una conexión a la base de datos, los cambios no se venreflejados en el servidor hasta que los apliquemos por medio del DataAdapter.

Para añadir una nueva fila a la tabla usaremos el método NewRow que crea un objeto nuevo DataRow vacíoque tiene el mismo esquema de la tabla. Esta nueva fila no esta asociada a la tabla sino que tiene las mismascaracterísticas. Cuando creemos el nuevo objeto DataRow podemos asignar los valores de los campos y

ACCESO A BASE DE DATOS CON ADO.NET

9

Page 97: Módulo_8_Acceso a bases de datos con ADO

agregarle el nuevo objeto a la tabla usando el método Add de la propiedad Rows, pasándole el objetoDataRow como parámetro.

‘Creamos una nueva fila.Dim myRow As DataRowmyRow = myCustomerTable . NewRow()

‘Definimos los valores de los campos.myRow(“Direccion”) = “Lagasca 40”myRow(“Ciudad”) = “Madrid”myRow(“CP”)=”28080”

‘Añadimos la nueva fila a la colección.myCustomerTable.Rows.Add (myRow)

Todo objeto DataRow tiene una propiedad RowState que nos indica el estado de la fila. Podemos comprobarel estado una fila antes de realizar una operación sobre ella y así aseguramos que cumple las condiciones quele hayamos establecido. La siguiente línea muestra el estado actual de la primera fila de la tabla:

Console.WriteLine (“Es estado de la fila es “ _& myCustomerTable. Rows (0).RowState.ToString( ))

Si queremos acceder a una determinada columna usaremos la propiedad Item de DataRow. Podemos usar unvalor de índice, un nombre de columna o un objeto.

Dim myRowNumber As Integer = 0Dim myColumnNumber As Integer = 2myCustomerTable . Rows (myRowNumber).Item (myColumnNumber)‘o…myCustomerTable. Rows(myRowNumber).Item(“Direccion”)‘o…Dim AddressColumn As DataColumnAddressColumn = myCustomerTable.Columns(“Direccion”)myCustomerTable.Rows(myRowNumber).Item(AddressColumn)

ACCESO A BASE DE DATOS CON ADO.NET

10

Page 98: Módulo_8_Acceso a bases de datos con ADO

También podremos acceder a la columna usando el nombre de la columna como parámetro del DataWor queestemos analizando. Es el método más aconsejable para referenciar una fila.

Dim myRow As DataRow = myCustomerTable. Rows (0)MessageBox . Show (myRow (“Direccion”))

Aquí vemos la primera fila de la tabla, y la hemos asignado a un objeto DataRow. Una vez que ya tenemosel DataWors podremos mostrar el contenido de la columna correspondiente pasándole el nombre.

ESTADOS DE FILA

Una fila puede tener varios estados. Cuando modificamos un registro, la fila correspondiente se indica comomodificada, esto nos permite revisar los cambios antes de ejecutarlos invocando el método AcceptChangesde la tabla. El método se encuentra disponible para objetos DataSet, DataTable, y DataRow y devuelve elRowState de cada objeto modificado a su valor sin modificar. De esta forma se hacen todos los cambiosefectuados desde que invocamos el último método AcceptChanges para la tabla con la que estamostrabajando. Podemos invocar este método en una fila ,así como para toda una tabla o un DataSet. Los valoresdisponibles del RowState son:

Si una fila es Added o Modified y se invoca AcceptChanges, la propiedad RowState se pone en estadoUnChanged. Si la fila se marca como Deleted s eliminaran al invocar el método AcceptChanges de la tabla.

ACCESO A BASE DE DATOS CON ADO.NET

11

Page 99: Módulo_8_Acceso a bases de datos con ADO

Para modificar una fila existente tenemos que acceder a la fila y columna y darle el nuevo valor.

Dim myRow As DataRow = myCustomerTabla . Rows( 0 )myRow( 0 ) = ” Lagasca 40 ”myCustomerTabla . AcceptChanges( )

Hemos accedido a la primera fila de datos y hemos actualizado el campo Direccion con nuevos datos.Asignado el nuevo valor el RowState cambia a Modified. Al invocar al método AcceptChanges , RowStaterecupera el valor Unchanged. Estos métodos únicamente actualizan las tablas del DataSet local y noreflejados en el servidor de base de datos. Si queremos enviar los cambios al servidor tendremos que usarel adaptador de datos.

ACTUALIZAR LA BASE DE DATOS

El método AcceptChanges solamente se actualizan los registros locales y no los de la base de datos. Losmétodos que usaremos a continuación presuponen que no hemos invocado el método AcceptChanges enninguno de los registros modificados antes de aplicar los cambios en el servidor. Tenemos un par de métodospara actualizar nuestra base de datos. Si queremos actualizar un DataSet, invocamos el método Update delDataAdapter. Podremos usar un DataSet, DataTables o una matriz de objetos DataRow y examinar la propiedadRowState para ver que filas han sufrido cambios. Después se ejecuta Insert, Update o Delete según el estadode la fila modificada. Cuando invocamos el método Update de un DataAdapter se actualizan los cambios enel servidor.

Dim myDataSetChanges As New DataSet( )‘obtenemos todos los cambiosmyDataSetChanges = myCustomerDataSet . GetChanges( )

‘obtenemos solamente los registros modificadosmyDataSetChanges = myCustomerDataSet . GetChanges( DataRowState . Modified )

‘obtenemos únicamente los registros eliminadosmyDataSetChanges = myCustomerDataSet . GetChanges( DataRowState.Deleted )

‘obtenemos solamente los registros añadidosmyDataSetChanges = myCustomerDataSet . GetChanges( DataRowState.Added)

‘Actualizamos los cambios de nuevo en la base de datosmyDataAdapter . Update ( myDataSetChanges )

ACCESO A BASE DE DATOS CON ADO.NET

12

Page 100: Módulo_8_Acceso a bases de datos con ADO

Ahora ampliaremos la aplicación añadiéndole opciones que permitan añadir, eliminar o actualizar los datos.A esta altura la aplicación solo admite una vista de solo lectura de la base de datos.

Necesitaremos configurar de nuevo el adaptador de datos de la tabla para poder ejecutar comandos Insert,Update y Delete en la tabla. Clic en el botón derecho sobre el DataAdapter y seleccionamos Configuraradaptador de datos.

ACCESO A BASE DE DATOS CON ADO.NET

13

Page 101: Módulo_8_Acceso a bases de datos con ADO

Se nos abrirá el Asistente de la configuración del adaptador de datos pidiéndonos una conexión a base dedatos. El nombre de la conexión debería aparecer. Si no aparece creamos una nueva haciendo clic en Nuevaconexión.

Pulsamos en siguiente cuando hayamos terminado.

La opción Usar instrucciones SQL debería estar seleccionada. Si no es así la seleccionamos y pulsamosSiguiente.

ACCESO A BASE DE DATOS CON ADO.NET

14

Page 102: Módulo_8_Acceso a bases de datos con ADO

La instrucción SQL select que existe debería aparecer en la ventana desplegable. Ya que vamos a insertar,borrar registros o actualizar querremos habilitar que la generación de comandos INSERT, UPDATE y DELETEpor parte del asistente sea automática. Clic en Opciones avanzadas:

El cuadro ofrece tres opciones. Seleccionaremos la primera casilla de verificación que habilita el resto delas casillas ya que deseamos todas las opciones. Clic en aceptar cuando terminemos.

ACCESO A BASE DE DATOS CON ADO.NET

15

Page 103: Módulo_8_Acceso a bases de datos con ADO

Miramos la instrucción Select en la siguiente pantalla y clic en siguiente.

En la última pantalla tenemos un resumen de los elementos que se generarán. Debemos indicar que se vana generar instrucciones INSERT, UPDATE y DELETE. Hacemos clic en Finalizar.

PROVEEDORES DE DATOS .NET

Están formados por una serie de clases usadas para conectarse a una fuente de datos, ejecutar comandos ydevolver registros. Son el nivel de datos. Los proveedores de datos .NET se les llama algunas vecesProveedores administrativos.

Tenemos dos tipos:

- El Proveedor de datos OLE DB, posibilita acceder a cualquier proveedor OLE DB incluyendo loscontroladores ODBC para Oracle, Microsoft Acces, Excel, FoxPro, Paradox, dBase y cualquier otrocontrolador ODBC o OLE DB nativo. Utiliza el espacio de nombre System.Data.OleDb.

- El Proveedor de datos SQL Server, específico para SQL Server 7.0 y posteriores. Es más rápido que elproveedor OLE DB porque no tiene que atravesar el nivel OLE DB ya que se comunica directamentecon el SQL Server. Utiliza el espacio de nombres System.Data.SqlCliente.

ACCESO A BASE DE DATOS CON ADO.NET

16

Page 104: Módulo_8_Acceso a bases de datos con ADO

El rendimiento de la aplicación y las especificaciones funcionales nos dirán cual es el mejor proveedor paranuestras necesidades.

Para usar el proveedor OLE DB en los proyectos incluimos el espacio de nombres SqlClient. ImportsSystem.Data.SqlCliente

Dentro de cada proveedor tendremos: los objetos Connection, DataAdapter,Command y DataReader.

EL OBJETO CONNECTION

Nos posibilita la apertura de una conexión con la fuente de datos. Podemos usar o el objeto OleDbConnectiono el objeto SqlConnection. Para el OLE DB usamos un Provider, DataSourcce, User Id y password en la cadenade conexión. Para el SQL necesitamos los mismos argumentos que para el proveedor OLE DB pero noespecificamos el provider que siempre es SQLOLEDB. Si la cadena de conexión para SQL especifica unparámetro Provider se genera excepción. La cadena dispone de varias propiedades muy usadas.

ACCESO A BASE DE DATOS CON ADO.NET

17

Page 105: Módulo_8_Acceso a bases de datos con ADO

La conexión se debe cerrar con Connection String. Al configurar la propiedad la cadena de conexión esanalizada para la detección de errores y se genera una excepción en el caso que contuviera una sintaxisincorrecta o contuviera valores que no fuesen correctos. Es necesario incluir un punto y coma entre cadapropiedad para posibilitar que el analizador distinga entre ellos. En los valores que queramos configurar sepueden usar comillas sencillas y no podemos usar símbolos. Todo valor dejado en blanco será ignorado. Enlos valores trae o false podemos usar ‘yes’ y ‘no’ ademas de ‘True’ y ‘False’.

Los argumentos mínimos para conectarse a una fuente de datos son Provider, Data Source e inicial Catalog.Si definimos un nombre de usuario y contraseña en la base de datos también necesitaremos ambos datos. Esteejemplo conecta a una base de datos Microsoft Access:

“Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Samples\Northwind.mdb;User Id=;Password=;”

Y Este a una Oracle:

“Provider=MSDAORA;Data Source=MyOracleDB;User Id=myId;Password=myPWD;”

Este otro conecta un objeto OleDbConnection a una base de datos SQL Server.

“Provider=SQLOLEDB Data Source=localhost;Initial Catalog=Pubs;User Id=;Password=;”

La agrupación de conexiones se habilita de forma predeterminada y puede proporcionar un mejorrendimiento de nuestras aplicaciones y servidores. Cuando nos creamos una conexión nueva se crea unaagrupación en función de la cadena de conexión. Cuando creemos una conexión la próxima vez si la cadenade conexión no cambió se usará la misma agrupación. Si la cadena por el contrario cambió de algún modo senecesitará una nueva agrupación. Este ejemplo crea una nueva agrupación de conexiones:

‘La conexión crea una nueva agrupaciónmyConnString = “Data Source=localhost;Inicial Catalog=NorthwindSQL;User Id=sa;”myConnection = New SqlConnection (myConnString)myConnection.Open( )

ACCESO A BASE DE DATOS CON ADO.NET

18

Page 106: Módulo_8_Acceso a bases de datos con ADO

Si creamos otra conexión con la misma cadena de conexión se añadirá a la primera agrupación:

‘Conexión añadida a una agrupación existente.myConnString2 = “Data Source=localhost;Inicial Catalog=NorthwindSQL;User Id=sa;”myConnection2 = New SqlConnection (myConnString)myConnection2.Open( )

EL OBJETO DATAADAPTER

Es el medio de comunicación entre la fuente de datos y el DataSet y puede ser un SqlDataAdapter o unOleDbDataAdapter. Si pretendemos recuperar o actualizar un registro, debemos usar propiedades deDataAdapter que hace referencia a objetos Command que contienen los comandos select, insert, update ydelete. Estos objetos Command son los que se comunican directamente con la fuente de datos para manipularlos datos según quiera el usuario. Los métodos más útiles de DataAdapter son Fill y Update. Fill completa unDataSet o tabla con la información especificada. Para rellenar el DataSet usamos el método Fill de unDataAdapter como se ve en este ejemplo:

Dim myDataSet As New DataSet( )myAdapter.Fill(myDataSet)

El método Update lo usamos para actualizar registros. Modificamos cualquier fila del DataSet e invocamosal método Update para que los cambios permanezcan en la fuente de datos:

myAdapter.Update(myDataSet)

EL OBJETO COMMAND

Lo usamos para configurar los comandos SELECT, INSERT, UPDATE y DELETE o procedimientos almacenadospara un objeto DataAdapter. Hay dos tipos, OleDbCommand y SqlCommand y cuatro subtipos: SelectCommand, InsertCommand, UpdateCommand y DeleteCommand. Este objeto lo usamos para enviar comandos a una base de datos mediante un objeto conexión.

Dim myConnection As New SqlConnectinn (myConnString)Dim myAdapter As new SqlDataAdapter( )Dim mySelectQuery As String = “select Address, City, PostalCode from Customers”myAdapter.SelectCommand = new SqlCommand(mySelectQuery, myConnection)

ACCESO A BASE DE DATOS CON ADO.NET

19

Page 107: Módulo_8_Acceso a bases de datos con ADO

Con esto se configura la propiedad SelectCommand del adaptador con un nuevo objeto SqlCommand, basadoen una consulta Select ensamblada en mySelectQuery y usando la conexión myConnection.

La configuración de InsertCommand es parecida, creamos un nuevo objeto SqlCommand con la instrucciónINSERT requerida y el objeto de conexión como parámetros y se asigna a la propiedad InsertCommand de unDataAdapter.

Dim myInsertQuery As String = “insert into Customers(Addres, City, PostalCode) values(@Address, @City,@PostalCode”myAdapter. InsertCommand = New SqlCommand (myInsertCuery, myConnection)

La asignación del los demás comandos sigue el mismo patrón. Si se trata de consulta UPDATE usamos elcódigo de la siguiente manera:

Dim myUpdateQuery As String =“update customers set Ardes=’200 ABC Street’ ,city=’Berbyly Hills’ whereCustomerId=’DUMON’ “

myAdapter.UpdateCommand = New SqlCommand(myUpdateQuery, myConnection)

De la misma manera para una consulta DELETE creamos un nuevo objeto SqlCommand y lo asignamos a lapropiedad DeleteCommand de un DataAdapter.

Dim myDeleteQuery As String = “Delete from Customers Where customerId=’DUMON’ ”myAdapter.DeleteCommand = New SqlCommand(myDeleteQuery, myConnection)

Si creásemos objetos Command manualmente en vez de usando los asistentes de datos, la claseSqlCommandBuilder proporciona una forma fácil de generar los comandos SQL insert, delete y update quelos asistentes de datos automáticamente generan. Esta clase fabrica instrucciones SQL para tablas sencillas.INSERT, DELETE y UPDATE basadas en la instrucción select que se proporciona. No tendremos tanto controlcomo si estuviésemos creando los comandos personalmente y el rendimiento no es tan bueno. El uso de SqlCommandBuilder es sencillo. Declaramos un nuevo objeto y lo pasamos al DataAdapter.

Dim myBuilder As New SqlCommandBuilder (myAdapter)

‘Mostramos la instrucción insert que se ha generado.MessageBox . Show(myBuilder.GetInsertCommand.CommandText)

ACCESO A BASE DE DATOS CON ADO.NET

20

Page 108: Módulo_8_Acceso a bases de datos con ADO

Ahora ya podremos ejecutar el método Update de nuestro DataAdapter para poder ejecutar los comandosinsert, delete y update en función de lo que nos haga falta. Los comandos se generan automáticamente alllamar al método Update.

Para recuperar los comandos que se utilizarán durante una actualización, utilizamos las propiedadesGetInserCommand, GetUpdateCommand Y GetDeleteCommand del objeto SqlCommandBuilder.

No estamos limitados a las instrucciones SQL cuando creamos el objeto Command ya que podremos tambiénllamar procedimientos almacenados.

Dim mySelectedCommand As SqlCommandmySelectCommand = New SqlCommand(“DeleteCustomer”, myConnection)mySelectCommand.CommandType = CommandType.StoredProcedure

Dim myParm As SqlParametermyPar = mySelectCommand.Parameters.Add(“@CustID”, SqlDbType.NvarChar,10)

myPar.Value = “DUMON”

myConnection .Open( )

dim RecordsAffected As Integer = mySelectCommand.ExecuteNoQuery( )myConnection.Close( )

Se crea un nuevo objeto Command y se le pasa el nombre del procedimiento almacenado, en nuestro casoDeleteCustomer. En el procedimiento almacenado DeleteCustomer hay una instrucción SQL como veremosahora. Es necesario especificar el tipo de comando que queremos ejecutar , concretamente un procedimientoalmacenado, utilizando el valor de la propiedad CommandType.StoredProcedure. Después se crea un nuevoSqlParameter que almacenaré el nombre del parámetro, el tipo, valor y tamaño. Entonces tendremos queabrir la conexión y ejecutar el procedimiento almacenado usando el método ExecuteNoQuery de Command.ExecuteNoQuery ejecutara la instrucción SQL o procedimiento asociado con el objeto Command y nosdevolverá la cantidad de registros afectados por la operación. Una vez terminamos cerramos la conexión.

CREATE PROCEDURE dbo.DeleteCustomer(

@ReturnValue INT= Null OUTPUT,@CustID INT

)As

Delete from Customers where customerid = @CustIDSelect @ReturnValue = @@RowCount

ACCESO A BASE DE DATOS CON ADO.NET

21

Page 109: Módulo_8_Acceso a bases de datos con ADO

Ejemplo de Acceso a Base de Datos ADO.NET

En este ejemplo veremos cómo acceder a una base de datos de Access, usando los objetos del espacio denombres OLEDB.

Los conceptos que se tratarán serán los siguientes:

- Crear una conexión a la base de datos.

- Mostrar las tablas de la base de datos indicada.

- Mostrar las columnas (o campos) de una tabla.

- Crear un DataAdapter para acceder a los datos devueltos por una consulta.

- Crear un DataSet basado en los datos asociados al DataAdapter.

- Crear nuevos registros.

- Modificar registros.

- Eliminar registros.

- Mostrar el contenido de la tabla en un control ListView.

ACCESO A BASE DE DATOS CON ADO.NET

22

Page 110: Módulo_8_Acceso a bases de datos con ADO

Nota del 20/Jul/2002:

He recibido varios mensajes diciendo que les daba error el ejemplo aquí puesto, he probado y efectivamente,me da error... le he puesto una captura (en el método Conecta) y me muestra un error de que la cadena SQLno es válida, pero si continuo, funciona bien.

Aunque, he de aclarar que ese error se produce en el código del ejemplo adjunto, si se deja el texto que pordefecto tiene la caja de textos en la que se indica la cadena SQL, si se deja en blanco, no se produce error.He modificado el código aqui mostrado, el cual puedes ver pulsando este link.

Los objetos a usar en el proyecto.

Los objetos que vamos a usar en este ejemplo, en su gran mayoría residen en el espacio de nombresSystem.Data.OleDb, aunque también se usarán objetos genéricos (DataSet, DataRow, DataColumn) queresiden en System.Data.

Para que nos sea más fácil declarar esos objetos, importaremos el espacio de nombres System.Data.OleDb ydado que usaremos procedimientos genéricos, estos los incluiremos en un módulo, al que llamaremos:ADONETUtil, veamos el código con las declaraciones de los objetos que usaremos en el proyecto:

Imports System.Data.OleDb

Module ADONETUtilFriend dbConnection As OleDbConnection‘Friend dbDataTable As Data.DataTableFriend dbDataSet As Data.DataSetFriend dbDataAdapter As OleDbDataAdapter‘Friend CadenaConexion As StringFriend CadenaSelect As String‘Friend ArchivoDatos As StringFriend NombreTabla As String = “Tabla1”‘

ACCESO A BASE DE DATOS CON ADO.NET

23

Page 111: Módulo_8_Acceso a bases de datos con ADO

La variable CadenaConexion será la cadena con la que conectaremos a la base de datos.

La variable CadenaSelect será el código SQL que usaremos para acceder a la tabla de esa base de datos.

La variable ArchivoDatos será el nombre completo de la base de datos (Path incluido).

La variable NombreTabla será el nombre que usaremos para identificar a los datos que cargaremos en elobjeto DataAdapter, ese nombre no tiene nada que ver con el nombre de la tabla a la que vamos a acceder,es sólo un nombre que usaremos con los distintos objetos de ADO.NET.

Conectar a una base de datos del tipo Access.

Para conectar a la base de datos y crear los objetos que cargarán la tabla (definida en la consulta SQLcontenida en la variable CadenaSelect), vamos a crear un procedimiento en el mismo módulo ADONETUtil:

Friend Sub Conectar(Optional ByVal nombreBaseDatos As String = “”, _Optional ByVal commandString As String = “”)

If nombreBaseDatos = “” ThennombreBaseDatos = ArchivoDatos

End IfArchivoDatos = nombreBaseDatosIf ArchivoDatos = “” Then

Exit SubEnd If‘If CadenaSelect = “” Then

CadenaSelect = “SELECT * FROM Table1”End IfIf commandString = “” Then

commandString = CadenaSelectEnd IfCadenaSelect = commandString‘CadenaConexion = “Provider=Microsoft.Jet.OLEDB.4.0; Data Source=” & ArchivoDatos‘Try

dbConnection = New OleDbConnection(CadenaConexion)

ACCESO A BASE DE DATOS CON ADO.NET

24

Page 112: Módulo_8_Acceso a bases de datos con ADO

Catch e As ExceptionMessageBox.Show(“Error al crear la conexión:” & vbCrLf & e.Message)Exit Sub

End Try‘dbConnection.Open()‘dbDataSet = New Data.DataSet()‘dbDataAdapter = New OleDbDataAdapter(CadenaSelect, dbConnection)‘Dim commandBuilder As New OleDbCommandBuilder(dbDataAdapter)‘dbDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey‘dbDataAdapter.Fill(dbDataSet, NombreTabla)‘ Cambio para comprobar que funciona, (20/Jul/02)‘ En la versión Architect me da error, pero continua funcionando.

‘ Aunque el error lo da si se pasa una cadena SQL que no es correcta,‘ por ejemplo, cuando se inicia la aplicación y se deja el texto por defecto.

TrydbDataAdapter.Fill(dbDataSet, NombreTabla)

Catch ex As ExceptionMessageBox.Show(“Error en Fill:” & vbCrLf & ex.Message)

End Try‘

End Sub

A este procedimiento se le pueden indicar dos parámetros:

El primero indicará el nombre de la base de datos (path incluido), mientras que el segundo será la instrucciónSQL que nos permitirá acceder a la tabla. Cuando veamos el código del formulario, tendremos ocasión de vercómo se llama a este procedimiento.

Lo que aquí tenemos que destacar es lo siguiente:

La cadena de conexión que tenemos que usar para conectar con la base de datos es igual que la usada en lasversiones anteriores de ADO, en esto no ha cambiado nada; se le indica el tipo de proveedor y el nombre dela base de datos.

ACCESO A BASE DE DATOS CON ADO.NET

25

Page 113: Módulo_8_Acceso a bases de datos con ADO

Creamos un objeto del tipo DataAdapter, éste será el que realmente nos permita acceder a los datos físicosde la base de datos, primero para rellenar el DataSet y posteriormente para actualizar los cambios realizadosen la base de datos.

Es importante saber que los datos contenidos en el objeto DataSet están en memoria y se acceden ymanipulan de forma independiente, sin ninguna relación directa con la base de datos original. Para que loscambios realizados en memoria se puedan reflejar de forma permanente en la base de datos, tenemos queusar el objeto DataAdapter.

Una vez creado el DataAdapter, al que se le indica la cadena de selección y la cadena de conexión o el objetodel tipo Connection. En este caso, le he indicado el objeto Connection, pero si no queremos crear unaconexión permanente, también podemos usar la misma cadena de conexión usada para crear el objetoConnection en lugar de ese objeto.

Para poder realizar cambios en la base de datos, hay que indicarle al DataAdapter los comandos SQL quehabría que usar para añadir, modificar y eliminar, pero esos comandos se pueden crear de forma automáticacreando un nuevo objeto del tipo CommandBuilder, al que se le pasará como parámetro el adaptador queusará dichos comandos, en realidad el objeto CommandBuilder no se usa nada más que para que de estaforma se asignen dichos comandos de actualización de datos.

Si la tabla a la que queremos acceder tiene clave principal (cosa que es común o debería serlo en todas lastablas), le indicamos mediante la asignación a la propiedad MissingSchemaAction el valor de añadir conclave. Si no hacemos esta asignación y la tabla tiene un campo que se incrementa automáticamente, nopodríamos crear varios registros (o filas) en memoria y después actualizar esas nuevas filas de formapermanente, ya que nos daría un error de que hay duplicidad en el campo (o columna) autoincremental.

Por último, llenamos el objeto DataSet con los datos del DataAdapter, el segundo parámetro es el nombreque le vamos a dar a la tabla virtual (la que se crea en memoria), si no le damos un nombre a esa tabla virtualdel DataSet, se asignará de forma predeterminada con el nombre Table. Es conveniente asignar un nombre,ya que un objeto DataSet permite tener en memoria distintos datos, de la misma o de otras tablas oconsultas. Ese nombre será el que usaremos para acceder a esos datos en memoria, ya que todos los accesosal contenido del DataSet, como he comentado antes, se realizan de forma desconectada, es decir sin relaciónninguna con la base de datos física.

ACCESO A BASE DE DATOS CON ADO.NET

26

Page 114: Módulo_8_Acceso a bases de datos con ADO

Los nombres de las tablas de una base de datos

Vamos a crear una función que devuelva una matriz (o array) del tipo String, con los nombres de las tablasde la base de datos.

Friend Function NombresTablas() As String()Dim nomTablas() As StringDim dataTable As Data.DataTableDim dbNull As System.DBNullDim restrictions() As Object = {dbNull, dbNull, dbNull, “TABLE”}Dim i As Integer‘If dbConnection Is Nothing Then

dbConnection = New Data.OleDb.OleDbConnection(CadenaConexion)End IfIf dbConnection.State <> ConnectionState.Open Then

dbConnection.Open()End If‘dataTable = dbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, restrictions)i = dataTable.Rows.Count - 1If i > -1 Then

ReDim nomTablas(i)For i = 0 To dataTable.Rows.Count - 1

nomTablas(i) = dataTable.Rows(i).Item(“TABLE_NAME”).ToString()Next

End If‘ Return nomTablas

End Function

Antes de llamar a esta función tendremos que tener asignada la cadena de conexión o, mejor aún, creadala conexión a la base de datos. Eso es lo que se hace en las primeras líneas, si el objeto del tipo Connectionno está creado, se crea un nuevo objeto, usando la cadena de conexión. En caso de que esté creado elobjeto, se comprueba si está abierta dicha conexión, de no ser así, se abre.

ACCESO A BASE DE DATOS CON ADO.NET

27

Page 115: Módulo_8_Acceso a bases de datos con ADO

A continuación asignamos un objeto del tipo DataTable con el “esquema” de las tablas contenidas en la basede datos a la que apunta el objeto Connection. El “truco” para conseguir los nombres de las tablas, está enel array restrictions, particularmente en el cuarto elemento: “TABLE”.

Recorremos el contenido del objeto DataTable y accedemos a cada una de las filas cuyo elemento contengala cadena “TABLE_NAME”, el cual nos dará el nombre de cada una de las tablas. Ese nombre lo asignamos acada uno de los elementos del array que estamos usando de forma interna, el cual será el que la funcióndevuelva.

Los nombres de los campos (o columnas) de una tabla.

Para saber los nombres de los campos o columnas de una tabla, usaremos el contenido del objeto DataSetque hace referencia a la tabla que hemos cargado mediante el DataAdapter, aunque también podría servirnospara acceder a cualquier tabla virtual contenida en el DataSet.

También vamos a crear una función que devuelva una matriz del tipo String:

Friend Function NombresColumnas() As String()Dim columna As Data.DataColumnDim i, j As IntegerDim nomCol() As String‘j = dbDataSet.Tables(NombreTabla).Columns.Count - 1ReDim nomCol(j)For i = 0 To j

columna = dbDataSet.Tables(NombreTabla).Columns(i)nomCol(i) = columna.ColumnName

NextReturn nomCol

End Function

Creo que el código es bastante auto-explicativo y no necesita más aclaración.

Asignar la cabecera de un control ListView con los nombres de las columnas o campos de una tabla.

Para terminar con el código del módulo ADONETUtil, vamos a ver unos métodos que usaremos para asignarlas columnas (o cabecera) de un ListView con los nombres de las columnas o campos de la tabla que vamosa utilizar.

ACCESO A BASE DE DATOS CON ADO.NET

28

Page 116: Módulo_8_Acceso a bases de datos con ADO

El método se llama AsignarCabeceraLista y tendrá dos implementaciones, una indicando sólo el nombre delListView y la otra en la que además se indicará un control ComboBox en el cual se asignarán también esosnombres de las columnas de la tabla.

Friend Sub AsignarCabeceraLista(ByVal ListView1 As ListView)Dim columna As Data.DataColumnDim i, j As Integer‘With ListView1

.View = View.Details

.FullRowSelect = True

.GridLines = True

.LabelEdit = False

.HideSelection = False

.Columns.Clear()End With‘Dim lasColumnas() As StringlasColumnas = NombresColumnas()‘If Not lasColumnas Is Nothing Then

For i = 0 To lasColumnas.Length - 1ListView1.Columns.Add(lasColumnas(i), 100, HorizontalAlignment.Left)

NextEnd If‘

End Sub

Friend Sub AsignarCabeceraLista(ByVal ListView1 As ListView, _ByVal cboCampos As ComboBox)

Dim i As Integer‘AsignarCabeceraLista(ListView1)cboCampos.Items.Clear()For i = 0 To ListView1.Columns.Count - 1

cboCampos.Items.Add(ListView1.Columns(i).Text)Next‘If cboCampos.Items.Count > 0 Then

cboCampos.SelectedIndex = 0End If

End Sub

ACCESO A BASE DE DATOS CON ADO.NET

29

Page 117: Módulo_8_Acceso a bases de datos con ADO

Creo que tampoco necesita explicación, ya que lo único que se hace es llamar a la función NombresColumnasy el contenido de ese array es el que se asigna a la cabecera del ListView que se ha indicado en el parámetro.En cuanto a la segunda implementación, se asigna al control ComboBox pasado como parámetro esos mismosnombres.

Cuando veamos el código de los formularios, sabremos cuando usar una u otra versión de este método.

Llenar un ListView con el contenido de una tabla.

El siguiente método del módulo ADONETUtil rellenará un control ListView con los datos de la tabla cargadaen el objeto DataSet.

Friend Sub LLenarLista(ByVal unListView As ListView)Dim i As IntegerDim lwItem As ListViewItemDim fila As Data.DataRow‘unListView.Items.Clear()‘For Each fila In dbDataSet.Tables(NombreTabla).Rows

For i = 0 To unListView.Columns.Count - 1If i = 0 Then

lwItem = unListView.Items.Add(fila(i).ToString)lwItem.Tag = fila

ElselwItem.SubItems.Add(fila(i).ToString)

End IfNext

NextEnd Sub

El código es también bastante simple, sólo quiero aclarar un detalle: La asignación del objeto fila al TAG delelemento del ListView.

Realmente no es necesario, pero yo lo utilizo esa fila para acceder a cada uno de los registros de la tabla,ya que al modificar los datos, sólo los reflejaremos en el contenido del ListView y de esa forma sabremos aque fila estamos accediendo. Cuando actualicemos los datos, usaremos el objeto que hemos guardado en la

ACCESO A BASE DE DATOS CON ADO.NET

30

Page 118: Módulo_8_Acceso a bases de datos con ADO

propiedad Tag del objeto ListViewItem, y ese mismo objeto será el que usaremos para eliminar una fila delDataSet.

Para terminar con el código del módulo, una función que usaremos para mostrar información de la base dedatos a la que estamos accediendo. En este caso es una función que recibe como parámetro un path completoy devuelve sólo el nombre de la base de datos:

Friend Function NombreBase(ByVal path As String) As String‘ Devolver sólo el nombre de la base de datosDim i As Integer‘i = path.LastIndexOf(“\“)If i > -1 Then

Return path.Substring(i + 1)End If

End Function

Aquí se podrían haber usado funciones “clásicas” de Visual Basic, como InStr o Mid, pero he preferido usarsus equivalentes de VB.NET, entre otras cosas porque forman parte del objeto String. En el caso deLastIndexOf, busca la última ocurrencia de la cadena indicada en el parámetro, si dicha cadena no formaparte del objeto, (en este caso la variable path), se devuelve un valor -1 y en caso de que si esté, se devuelvela posición, pero hay que tener en cuenta que la primera posición está representada por el valor cero.

El formulario principal

Este es el aspecto del formulario principal (Form1) en tiempo de diseño:

ACCESO A BASE DE DATOS CON ADO.NET

31

Page 119: Módulo_8_Acceso a bases de datos con ADO

El formulario principal en tiempo de diseño

Este formulario permitirá que se arrastre una base de datos y ese nombre se asignará a la caja de textos delnombre de la base de datos. Los controles tienen asignados los valores de la propiedad Anchor para que seajusten al tamaño que el usuario quiera darle al formulario, esos detalles podremos verlo en el códigocompleto, ya que aquí sólo mostraré la parte que realmente interesa, es decir lo que está relacionado conel acceso a la base de datos. Empecemos por el código del botón “Mostrar tablas” y el evento producido cuando se selecciona una tabladel ComboBox:

Private Sub btnAbrirBase_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnAbrirBase.Click

‘Conectar(txtNombreBase.Text, txtSelect.Text)‘‘Dim nomTablas() As StringDim i As Integer‘nomTablas = NombresTablas()cboTablas.Items.Clear()If Not nomTablas Is Nothing Then

For i = 0 To nomTablas.Length - 1cboTablas.Items.Add(nomTablas(i))

NextEnd IfIf cboTablas.Items.Count > 0 Then

cboTablas.SelectedIndex = 0End If

End Sub

Private Sub cboTablas_SelectedIndexChanged(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles cboTablas.SelectedIndexChanged

txtSelect.Text = “SELECT * FROM “ & cboTablas.Text‘‘’ Si se quieren mostrar individualmente los nombres de los campos

ACCESO A BASE DE DATOS CON ADO.NET

32

Page 120: Módulo_8_Acceso a bases de datos con ADO

‘Dim lasColumnas() As String‘Dim s As String, i As Integer‘’‘CadenaSelect = txtSelect.Text‘lasColumnas = NombresColumnas()‘For i = 0 To lasColumnas.Length - 1‘ s &= lasColumnas(i) & “, “‘Next‘’ Quitar la última coma‘i = s.LastIndexOf(“, “)‘s = s.Substring(0, i)‘s = “SELECT “ & s & “ FROM “ & cboTablas.Text‘txtSelect.Text = s

End Sub

El primer procedimiento intercepta la pulsación en el botón y asigna los nombres de las tablas en el combo.El segundo, simplemente crea la cadena SQL que se usará para acceder a dicha tabla.

El código que está comentado sirve para mostrar los nombres de los campos o columnas de forma individual.

Cuando pulsamos en el botón “Mostrar”, se muestra el contenido de la tabla indicada, información que seobtiene del DataSet que contiene los datos en memoria. Aunque, el código mostrado, realmente refresca esainformación, esto lo he hecho así para que al volver de modificar los datos, se pueda comprobar que losdatos realmente se han guardado en la base de datos.

Private Sub btnMostrar_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnMostrar.Click

‘With ListView1

.View = View.Details

.FullRowSelect = True

.GridLines = True

.LabelEdit = False

.HideSelection = False

.Columns.Clear()End With‘‘ Volver a reconectar para actualizar los datos desde la baseIf Not dbConnection Is Nothing Then

dbConnection.Close()End If

ACCESO A BASE DE DATOS CON ADO.NET

33

Page 121: Módulo_8_Acceso a bases de datos con ADO

Conectar(txtNombreBase.Text, txtSelect.Text)‘AsignarCabeceraLista(ListView1)LLenarLista(ListView1)

End Sub

Como podemos comprobar, aquí se llaman a los métodos del módulo ADONETUtil, por tanto al principio delcódigo del formulario debemos hacer la importación del espacio de nombres de ese módulo para no tenerque especificarlo cada vez que queramos acceder a cualquiera de los procedimientos o variables en eldeclarado:

‘ Importamos el módulo con las declaraciones de los objetos a usarImports ADONET1.ADONETUtil

ADONET1 es el nombre del “espacio de nombres” (Namespace) de este proyecto.

Para acabar con el código de este formulario, veamos los eventos que se producen al cargarse el formulario(Load) y al cerrarse (Closing), además del evento producido al pulsar en el botón “Mostrar”, el cual mostraráel formulario en el que se editan los datos de la tabla indicada.

Private Sub Form1_Load(ByVal sender As Object, _ByVal e As System.EventArgs) _Handles MyBase.Load

Me.txtNombreBase.Text = “E:\gsCodigo\Vb6\Pruebas\Bases\db2000NET.mdb”‘ArchivoDatos = txtNombreBase.TextCadenaConexion = “Provider=Microsoft.Jet.OLEDB.4.0; Data Source=” & ArchivoDatos‘With ListView1

.View = View.Details

.FullRowSelect = True

.GridLines = True

.LabelEdit = FalseEnd With‘cboTablas.Text = “”

End Sub

ACCESO A BASE DE DATOS CON ADO.NET

34

Page 122: Módulo_8_Acceso a bases de datos con ADO

Private Sub Form1_Closing(ByVal sender As Object, _ByVal e As System.ComponentModel.CancelEventArgs) _Handles MyBase.Closing

‘ Cerrar la conexiónTry

If dbConnection.State = ConnectionState.Open ThendbConnection.Close()

End IfCatchEnd Try

End Sub

Private Sub btnModificar_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnModificar.Click

Dim f2 As New Form2()With f2

.DataSource = txtNombreBase.Text

.CommandString = txtSelect.Text

.ShowDialog()End WithbtnMostrar_Click(btnMostrar, e)

End Sub

En el evento Load, asignamos los valores iniciales, en el evento Closing, comprobamos si tenemos la conexiónabierta y de ser así la cerramos, debido a que puede ser que se cierre el formulario sin necesidad de habercreado dicho objeto, interceptamos el error que se pudiera producir.

Por otro lado, cuando pulsamos en el botón Modificar, creamos una nueva instancia del formulario en el quemodificaremos la información y asignamos los valores de la base de datos y la cadena SQL que usaremos paraconectar, esto lo hago así por si se pulsa en dicho botón sin haber creado la conexión.

El formulario de edición de datos

Para terminar con este ejemplo de acceso a datos usando ADO.NET, veamos el formulario que usaremos paramodificar la información de la base de datos.

ACCESO A BASE DE DATOS CON ADO.NET

35

Page 123: Módulo_8_Acceso a bases de datos con ADO

El aspecto del formulario (FORM2) será el mostrado en la siguiente imagen:

El formulario de introducción de datos

En este formulario, los controles también están “anclados” para que se adapten al tamaño que el usuarioquiera darle al formulario. Empecemos por las variables o propiedades que este formulario expone al mundo externo:

‘ Importamos el módulo con las declaraciones de los objetos a usarImports ADONET1.ADONETUtil

Public Class Form2Inherits System.Windows.Forms.Form

Friend DataSource As StringFriend CommandString As String‘Private lwItemActual As ListViewItem

ACCESO A BASE DE DATOS CON ADO.NET

36

Page 124: Módulo_8_Acceso a bases de datos con ADO

También usamos el Imports para poder usar los procedimientos del módulo ADONETUtil y declaramos dospropiedades: DataSource y CommandString, las cuales usaremos para acceder a la base de datos. La variable lwItemActual hará referencia al elemento del ListView que esté actualmente seleccionado. En el evento Load del formulario, se asignarán algunos valores por defecto y se mostrará el contenido de latabla indicada en el ListView:

Private Sub Form2_Load(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles MyBase.Load

Me.txtCampo1.Text = “”‘‘ para usar este formulario como formulario inicialIf DataSource = “” Then

DataSource = “E:\gsCodigo\Vb6\Pruebas\Bases\db2000NET.mdb”End IfIf CommandString = “” Then

CommandString = “SELECT * FROM Table1”End If‘lblInfo.Text = “Base: “ & NombreBase(DataSource) & “, Select: “ & CommandString‘If dbConnection Is Nothing Then

Conectar(DataSource, CommandString)End If‘AsignarCabeceraLista(ListView1, cboCampos)LLenarLista(ListView1)‘Me.AcceptButton = btnAsignar

End Sub

ACCESO A BASE DE DATOS CON ADO.NET

37

Page 125: Módulo_8_Acceso a bases de datos con ADO

Cuando seleccionamos un nuevo elemento del ListView, se asigna la variable que contiene el elemento actualy se muestra la información o datos de dicha fila.

Private Sub ListView1_SelectedIndexChanged(ByVal sender As Object, _ByVal e As System.EventArgs) _Handles ListView1.SelectedIndexChanged

TrylwItemActual = ListView1.SelectedItems(0)

CatchEnd Try

End SubPrivate Sub ListView1_Click(ByVal sender As Object, _

ByVal e As System.EventArgs) _Handles ListView1.Click, cboCampos.SelectedIndexChanged

TrylwItemActual = ListView1.SelectedItems(0)MostrarCampo()

CatchEnd Try

End Sub

Como podemos comprobar, el procedimiento ListView1_Click realmente intercepta dos eventos, el eventoClick del ListView y el evento SelectedIndexChanged del Combo, de forma que se muestre la información delcampo seleccionado en el ComboBox. De eso se encarga el procedimiento MostrarCampo:

Private Sub MostrarCampo()Dim i As Integer‘Try

i = cboCampos.SelectedIndexIf i = 0 Then

txtCampo1.Text = lwItemActual.TextElseIf i > -1 Then

txtCampo1.Text = lwItemActual.SubItems(i).TextEnd If

CatchEnd Try

End Sub

ACCESO A BASE DE DATOS CON ADO.NET

38

Page 126: Módulo_8_Acceso a bases de datos con ADO

Este procedimiento simplemente muestra el contenido del campo que está seleccionado en el controlComboBox.

Asignar los datos

Cuando pulsamos en el botón Asignar, el cual hemos asignado como botón “Aceptar” del formulario, es decirel que tomará el foco cuando pulsemos la tecla Intro, se asignarán los cambios realizados al campo (ocolumna) que estamos editando:

Private Sub AsignarCampo(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnAsignar.Click

‘ Asignar al ListView el campo modificadoDim i As Integer‘i = cboCampos.SelectedIndexIf i = 0 Then

lwItemActual.Text = txtCampo1.TextElseIf i > -1 Then

lwItemActual.SubItems(i).Text = txtCampo1.TextEnd If

End Sub

Eliminar una fila

Cuando pulsamos en el botón Eliminar, borramos la fila seleccionada del ListView y también esa misma filadel DataSet, y como comenté anteriormente, en la propiedad Tag del elemento del ListView tenemos unareferencia a la fila de datos, por tanto usamos ese objeto para eliminar la fila de la colección Rows delobjeto DataSet, ya que el método Remove de la colección Rows acepta como parámetro un objeto del tipoDataRow:

Private Sub btnEliminar_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnEliminar.Click

‘ Eliminar la fila indicadaDim fila As Data.DataRow‘fila = CType(ListView1.SelectedItems(0).Tag, Data.DataRow)dbDataSet.Tables(NombreTabla).Rows.Remove(fila)ListView1.Items.Remove(ListView1.SelectedItems(0))

End Sub

ACCESO A BASE DE DATOS CON ADO.NET

39

Page 127: Módulo_8_Acceso a bases de datos con ADO

Crear una nueva fila (o registro)

Para crear un nuevo registro (o fila), tendremos que asignar unos valores nulos o por defecto a una nuevafila creada en la memoria, después esa fila la añadiremos a la tabla que mantenemos en el DataSet.Debido a que algunos campos no permiten valores nulos, tendremos que tener ese detalle en cuenta y de serasí, asignaremos un valor adecuado al tipo de datos de cada una de las columnas (o campos) del registro quehemos creado, esto lo conseguimos comprobando el tipo de datos de cada una de las columnas de la nuevafila. Hay que tener en cuenta que los tipos de datos se guardan usando el que se define en .NET Framework,no los tipos que utiliza Visual Basic, por tanto, para saber si el tipo de una columna es del tipo Integer,tendremos que usar System.Int32, de todas formas, para saber el tipo de dato, (que lo da la propiedadDataType del objeto DataColumn), he utilizado la conversión a cadena generada por ToString, por lo quedicho tipo se convierte en el formato “System.Tipo”, veamos el código para aclarar todo este lío:

Private Sub btnNuevo_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnNuevo.Click

‘ Añadir una nueva fila (o registro)Dim fila As Data.DataRowDim i As IntegerDim lwItem As ListViewItemDim columna As Data.DataColumn‘fila = dbDataSet.Tables(NombreTabla).NewRowfila.BeginEdit()For i = 0 To dbDataSet.Tables(NombreTabla).Columns.Count - 1

columna = dbDataSet.Tables(NombreTabla).Columns(i)‘Debug.WriteLine(columna.DataType.ToString)If columna.AutoIncrement = False Then

Select Case columna.DataType.ToStringCase “System.String”

fila(i) = columna.ColumnNameCase “System.Boolean”

fila(i) = FalseCase “System.Byte”, “System.SByte”

fila(i) = CByte(0)Case “System.Char”

fila(i) = “ “c

ACCESO A BASE DE DATOS CON ADO.NET

40

Page 128: Módulo_8_Acceso a bases de datos con ADO

Case “System.DateTime”, “System.TimeSpam”fila(i) = Now

Case “System.Decimal”, “System.Double”, “System.Single”fila(i) = 0

Case Else‘Case “System.Int32”,”System.UInt32”‘ fila(i) = 0If columna.DataType.ToString.IndexOf(“System.Int”) > -1 Then

fila(i) = 0ElseIf columna.DataType.ToString.IndexOf(“System.UInt”) > -1 Then

fila(i) = 0End If

End SelectEnd If

Nextfila.EndEdit()‘ Añadir la fila a la tabladbDataSet.Tables(NombreTabla).Rows.Add(fila)‘‘ Mostrar la nueva fila en el ListViewFor i = 0 To ListView1.Columns.Count - 1

If i = 0 ThenlwItem = ListView1.Items.Add(fila(i).ToString)lwItem.Tag = fila

ElselwItem.SubItems.Add(fila(i).ToString)

End IfNext‘

End Sub

Lo que en este evento hacemos es crear una nueva fila mediante el método NewRow, asignamos los campos(o columnas) de dicha fila y la añadimos a la colección Rows de la tabla. Hay que tener en cuenta que al crearuna nueva fila con NewRow no se añade a la colección de filas (o registros), simplemente se devuelve unobjeto que está preparado para que se le asignen los datos correspondientes. Antes de asignar cada una delas columnas, comprobamos si dicha columna está marcada como autoincremental, de ser así, no asignamosnada, ya que es el propio DataAdapter el que se encarga de asignar el valor de dicha columna.

ACCESO A BASE DE DATOS CON ADO.NET

41

Page 129: Módulo_8_Acceso a bases de datos con ADO

En este punto quiero hacer una aclaración, debido a que los datos los estamos asignando a un objeto quemantiene la información en la memoria, si existen varias aplicaciones que acceden a la misma base de datosy cada una de ellas crea nuevas filas, el valor asignado al campo (o columna) AutoIncrement puede que nosea el que definitivamente tenga en la base de datos. Por tanto, debemos tener esto presente si el valorasignado a esa columna lo utilizamos para otros menesteres.

Una vez que hemos añadido la nueva fila a la tabla, asignamos el contenido de la misma al ListView y tambiénasignamos a la propiedad Tag una referencia a dicha fila.

Guardar la información en la base de datos

Por último vamos a ver cómo pasar la información mantenida en la memoria a la base de datos, con idea deque los cambios realizados se queden guardados permanentemente.

Esto lo hacemos cuando el usuario pulsa en el botón de “Actualizar Base” y el código usado es el siguiente:

Private Sub btnActualizarBase_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) _Handles btnActualizarBase.Click

‘ Actualizar la base de datos con los cambios realizadosDim fila As Data.DataRowDim i, j As IntegerDim lwItem As ListViewItemDim columna As Data.DataColumn‘lblInfo.Tag = lblInfo.TextlblInfo.Text = “Actualizando los datos...”lblInfo.Refresh()Try

For i = 0 To ListView1.Items.Count - 1lwItem = ListView1.Items(i)fila = CType(ListView1.Items(i).Tag, Data.DataRow)fila.BeginEdit()j = 0For Each columna In dbDataSet.Tables(NombreTabla).Columns

If j = 0 ThenIf columna.AutoIncrement = False Then

fila(j) = lwItem.TextEnd If

ACCESO A BASE DE DATOS CON ADO.NET

42

Page 130: Módulo_8_Acceso a bases de datos con ADO

ElseIf columna.AutoIncrement = False Then

fila(columna.ColumnName) = lwItem.SubItems(j).TextEnd If

End If‘ j += 1

Nextfila.EndEdit()

Next‘‘dbDataAdapter.Update(dbDataSet, NombreTabla)dbDataSet.AcceptChanges()‘‘lblInfo.Text = CStr(lblInfo.Tag)

Catch errActualizar As ExceptionlblInfo.Text = errActualizar.MessageMsgBox(errActualizar.Message)

End TryEnd Sub

En este procedimiento actualizamos la información de cada una de las filas, para ello usamos el objetoalmacenado en la propiedad Tag de cada uno de los elementos del ListView que como recordarás era enrealidad una referencia a cada una de las filas de la tabla, (realmente un objeto del tipo DataRow).Recorremos cada una de las columnas y asignamos sólo los datos si no es una columna del tipo AutoIncrement.La llamada a los métodos BeginEdit y EndEdit de cada fila es para que no se produzcan los eventos asociadosa un objeto de este tipo, no son realmente necesarios para poder cambiar los contenidos de las columnas.

Una vez que hemos asignado todos los datos del ListView, llamamos al método Update del DataAdapter, estemétodo es el que realmente hace que los datos se guarden físicamente en la base de datos.

Después llamamos al método AcceptChanges del objeto DataSet para que “sepa” que hemos aceptado lanueva información y marque la información de forma que sean iguales a los datos que tiene la base de datosreal.

ACCESO A BASE DE DATOS CON ADO.NET

43

Page 131: Módulo_8_Acceso a bases de datos con ADO

Y esto es todo... que no es poco... en otras ocasiones veremos cómo acceder a los datos de una base de datosmediante controles enlazados y con un DataGrid que es en realidad la forma más fácil de hacerlo. Realmente si hubiésemos usado ese control, no tendríamos que haber escrito la mayoría del código que hemostrado, pero como se que hay gente que le gusta tener un control “casi” total sobre cómo se accede a lainformación... pues eso, que aquí está la forma “difícil” de hacerlo y ya habrá ocasión de ver la forma “fácil”.En otra ocasión, veremos este mismo código aplicado a una base de datos de SQL Server.

ACCESO A BASE DE DATOS CON ADO.NET

44

Page 132: Módulo_8_Acceso a bases de datos con ADO

Módulo: ACCESO A BASE DE DATOS CON ADO.NET – Caso prácticoLa empresa Adventure Works Cycles se dedica a la fabricación y comercialización de todo tipo de bicicletasorientadas a los deportes de aventura.Estaba, originalmente, ubicada en los Estados Unidos, pero su éxito les ha obligado a un rápido crecimientopor todo el mundo.Pero, no han pensado en la ampliación de su departamento de sistemas y desarrollo. Para la implantación de su sucursal en España necesitan de tu ayuda como desarrollador.

Ejercicio 1Para su nueva fábrica en España necesitan que los empleados puedan consultar el despiece de cadauno de sus productos, pero carecen de la pantalla con las cabeceras de columnas traducidas. Por lo tanto, has de crear un programa de escritorio en el que los empleados puedan seleccionarun producto de una lista desplegable y mostrar todos los componentes del mismo en un controlDataGridView, con las cabeceras adecuadamente traducidas.Para la lista de selección habrá que recurrir a la tabla Production.Product, mostrando el campoName, pero utilizando el valor del campo ProductID para el enlace a la cuadrícula.Para lo cual ya tienen, en su base de datos AdventureWorks, implantada en SQL Server 2008, unatabla Production.BillOfMaterials, en la cual figura, para cada producto vendido, denominadoProductAssemblyID, la composición de su fabricación.Pero esta tabla sólo tiene el código de los componentes de los productos, por lo que será necesariocruzarla con la tabla de productos, Production.Product, para hallar la descripción de los mismos,mediante la relación Production.BillOfMaterials.ComponentId = Production.Product.ProductID.De los campos de estas tablas será necesario recuperar los siguientes:

BillOfMaterials.ProductAssemblyID El producto fabricadoBillOfMaterials.ComponentId Componente del producto fabricado.Product.Name Descripción del componente.BillOfMaterials.PerAssemblyQty Cantidad empleada.

ACCESO A BASE DE DATOS CON ADO.NET CASO PRÁCTICO

1

© élogos Conocimiento, S.L. Madrid 2009. Todos los derechos de Propiedad Intelectual e Industrial de esta obra pertenecen a élogos Conocimiento, S.L.

Page 133: Módulo_8_Acceso a bases de datos con ADO

Ejercicio 2Dado que esta ampliación les ha pillado un poco a contrapié, no han podido prepara la infraestruc-tura adecuada para nuestro país, por lo que habrá que insertar, en la tabla Person.StateProvincetodas y cada una de las provincias Españolas.Sabiendo que dicha tabla contiene los siguientes campos, que han de ser rellenados según se indica:

- StateProvinceID, código de la provincia, auto numérico.- StateProvinceCode, código alfabético de la provincia, String.- CountryRegionCode, código del país “ES”.- IsOnlyStateProvinceFlag, 0- Name, Descripción, String- TerritoryID, código del territorio, 6 para Europa- Rowguid, identificador de columna, interno a SQL Server- ModifiedDate, la fecha del día

ACCESO A BASE DE DATOS CON ADO.NET CASO PRÁCTICO

4