Logo Studenta

sql server (1)

¡Este material tiene más páginas!

Vista previa del material en texto

1 
 
Tutorial de SQL Server 2005 Express 
En este tutorial, aprenderá los fundamentos para desarrollar aplicaciones con la versión Express 
de SQL Server 2005. El objetivo del tutorial no es cubrir en gran detalle todos los aspectos de SQL 
Server 2005 Express, pero si aportar una idea general del producto y su integración con el resto 
de herramientas Express (Visual Basic Express, Visual C# Express, y Visual J# Express 
El tutorial cubrirá los siguientes puntos: 
Módulo 1: Introducción a SQL Server Express 
• Requisitos del sistema, instalación del producto, y descripción de sus componentes. 
• Integración del producto con otras versiones Express; durante el tutorial se trabajará con la 
versión Express de Visual Basic; sin embargo todos los ejemplos y demostraciones usados son 
aplicables a Visual C#, y J#. 
• Proceso de despliegue de aplicaciones desarrolladas con Visual Basic Express. Conceptos 
XCOPY, instancias de usuario no-administrador, y duplicación de datos. 
• Proveedores de acceso a datos disponibles. A la hora de conectar a un servidor de base de 
datos como SQL Server 2005 Express, el nexo de comunicación entre el servidor y la 
aplicación cliente, es el proveedor de acceso a datos; se hablará e introducirá brevemente los 
proveedores de acceso a datos disponibles. 
Módulo 2: Creación de bases de datos con Visual Studio 
• Objetos básicos del sistema. Conocerá aspectos de la base de datos como su creación tipos de 
datos disponibles en SQL Server 2005, creará tablas, restricciones (constraints), relaciones, y 
teoría relativa a la creación de índices, y su idoneidad. 
• Conocerá como realizar consultas a las tablas de la base de datos, cláusulas de las sentencias, 
agrupaciones, joins, etc. También conocerá una nueva característica del producto que son las 
expresiones de tablas comunes (CTE). Además aprenderá a hacer sentencias de inserción, 
actualización, y borrado. 
Módulo 3: Programación de base de datos 
• Procedimientos almacenados. Conocerás los fundamentos para crear procedimientos 
almacenados en la base de datos. 
• Triggers. Introducción al uso de triggers en SQL Server 2005 Express; veremos los triggers 
"tradicionales" (llamados DML, los que se activan por modificaciones de datos), y también 
veremos los nuevos triggers que se activan por cambio en el esquema de base de datos 
(DDL). 
• Funciones definidas de usuario. Veremos como crear UDFs, y los tipos de funciones definidas 
de usuario que existen. 
Módulo 4: Conceptos avanzados 
• Conceptos de seguridad de objetos, esquemas, y credenciales de inicio de sesión. Se 
introducirá el nuevo paradigma de seguridad basado en esquemas. 
 2 
• Trasaccionalidad y niveles de aislamiento. Se cubrirán los niveles de aislamiento y cómo SQL 
Server 2005 garantiza la atomicidad, consistencia, integridad, y durabilidad de las 
transacciones. 
• Soporte Nativo XML. Conocerá en qué consiste el soporte nativo de XML, uso de las columnas 
tipo XML, indexación, y consultas XQuery. 
• Integración del CLR. Conocerá la nueva posibilidad de crear objetos en la base de datos 
usando cualquier lenguaje .NET como VB.NET, o C#. 
Aunque el tutorial no está escrito para un tipo de audiencia determinada, es recomendable que el 
alumno tenga conceptos de desarrollo de aplicaciones cliente-servidor, y fundamentos de bases 
de datos que aunque durante el curso se irán cubriendo en mayor o menor profundidad, ayudarán 
al alumno a una rápida comprensión de las lecciones. 
En la introducción del tutorial, se verá cómo instalar el producto y los diferentes proveedores de 
acceso a datos que se pueden utilizar. En el segundo módulo, se verá cómo aprovechar la 
integración entre las herramientas de desarrollo de Visual Basic Express con el motor relacional de 
SQL Server 2005 Express para crear bases de datos, tablas, vistas, y otros objetos. En el tercer 
módulo, aprenderá conceptos básicos sobre procedimientos almacenados, triggers, y UDFs, y para 
finalizar el tutorial, aprenderá otros conceptos relacionados con seguridad, transacciones, y 
niveles de aislamiento. A su vez, conocerá nuevas funcionalidades del producto como soporte 
nativo XML, y la integración del CLR en el motor relacional de SQL Server 2005. 
Recuerde que si quiere poner en práctica este curso tiene disponibles una versión sin limitaciones 
de Visual Basic 2005 Express, que incluye la base de datos SQL Server 2005 Express. 
¡Que disfrutes del curso! 
Solid Quality Learning University http://www.sqlu.com 
Solid Quality Learning Iberoamericana http://www.SolidQualityLearning.com 
Diseñado, y editado por los siguientes mentores de Solid Quality Learning: 
http://www.SolidQualityLearning.com/aboutUs.aspx: 
• Miguel Egea (megea@sqlu.com) 
MVP SQL Server 
Director de Servicios Corporativos 
• Eladio Rincón (erincon@sqlu.com) 
MVP SQL Server 
Director de Tecnologías de Bases de Datos 
• Eugenio Serrano (eserrano@sqlu.com) 
MVP ASP/ASP.NET 
• Antonio Soto (asoto@sqlu.com) 
MCT, Director de Formación 
Agradecimientos 
• Queremos agradecer a Alfonso Rodríguez, David Carmona, y Luís Mazario de Microsoft Ibérica 
su soporte y colaboración durante las fases de diseño y desarrollo de este curso. 
Muchas gracias!!! 
 3 
1. Introducción a SQL Server 2005 Express 
Durante el módulo, verá cuales los requisitos hardware/software necesarios para instalar SQL 
Server 2005 Express, y cómo realizar la instalación del producto. Se introducirá al alumno 
brevemente los componentes del producto, enfocado en las necesidades del desarrollador de 
software. A su vez se verá cómo se integra SQL Server 2005 Express con las herramientas de 
desarrollo de las ediciones Express. Para finalizar se presentarán los drivers de acceso a datos que 
se usarán para conectar a SQL Server 2005 Express. 
1.1. Instalación de SQL Server 2005 Express y sus componentes 
En esta lección, conocerá los requisitos para instalar SQL Server 2005 Express; además, verá las 
diferentes opciones disponibles durante la instalación asistida. A continuación se le introducirá los 
componentes instalados, explicándose su funcionalidad. Para finalizar la lección se hablará de 
otros componentes disponibles con el producto como código y bases de datos de ejemplo, y 
documentación del producto (Libros en pantalla). 
1.1.1. Requisitos del sistema 
La instalación del SQL Server 2005 Express tiene los siguientes requerimientos: 
- Requisitos 
previos de 
software 
- Microsoft .NET Framework 
- SP1 de Microsoft Internet Explorer 6.0 o posterior 
- RAM 
- Mínimo: 192 MB 
- Recomendado: 512 MB o más 
- Espacio en el 
disco duro 
- 600 MB de espacio libre 
- Procesador 
- Compatible con Pentium III o superior 
- Mínimo: 500 MHz 
- Recomendado: 1 GHz o más 
- Sistema 
operativo 
- Windows Server 2003 Standard Edition, Enterprise Edition, 
Datacenter Edition 
- Windows XP Professional, Home Edition (SP2 o posterior) 
- Windows 2000 Professional, Server, Advanced Server, Datacenter 
Server (SP4 o posterior) 
1.1.2. Proceso de instalación 
La instalación de SQL Server 2005 Express se puede realizar de dos formas: 
1.1.2.1. Como parte de la instalación de algún producto Express. 
Si se instala como parte de la instalación de algún producto Express (por ejemplo Visual 
Basic Express), el proceso de instalación le pedirá si desea incluir SQL Server 2005 Express 
en la instalación: en la imagen puede ver la ventana en la que se le solicita la opción (la 
instalación por defecto no incluye instalar SQL Server 2005 Express). 
 4 
 
 5 
1.1.2.2. Como instalación independiente. 
Si se instala de forma independiente, el proceso de instalación requiere los siguientes 
pasos: 
El primer paso de la instalación consiste en instalar Microsoft .NET Framework 2.0 que es 
uno de los requisitos de la instalación; si ya está instalado previo al proceso de instalación, 
este paso será omitido. La actualización desde versiones anteriores de .NET Framework 
está soportada hasta la versión 1.1, en caso de haberinstalado una versión posterior, 
deberá desinstalarla antes de instalar SQL Server 2005 Express; en otras palabras, la 
actualización se puede realizar sólo desde versiones soportadas de .NET Framework. 
 
 6 
Ventana de condiciones de EULA; aceptar los términos de la licencia y condiciones y pulsar 
Siguiente. 
 
 7 
Ventana de bienvenida de instalación de los prerrequisitos necesarios para SQL Server 
2005 Express; pulsar Instalar. 
 
 8 
Ventana de finalización de instalación de los prerrequisitos; pulsar Siguiente. 
 
 9 
Ventana de bienvenida al asistente de instalación de SQL Server 2005 Express; pulsar 
Siguiente. 
 
 10 
Ventana de comprobación de requerimientos del sistema; si la comprobación ha sido 
satisfactoria, todas las opciones aparecerán con la opción de verificación en color verde, en 
caso de haber algún requerimiento no severo, aparecerá en color amarillo; si hay algún 
requerimiento crítico que no se cumple, aparecerá en color rojo y no podrá seguirse con el 
proceso de instalación. Pulsando en el botón Report, podrá ver cuales son los requisitos no 
cumplidos para poder preparar al sistema para cumplirlos; por ejemplo, si no se cumplen 
los requerimientos de ASP.NET, podrá salir de la instalación, actualizar ASP.NET, y volver a 
realizar la instalación. Si la comprobación ha sido satisfactoria, pulse Siguiente. 
 
 11 
Introduzca la información de registro, desmarque la opción Ocultar opciones avanzadas de 
configuración, y pulse Siguiente. 
 
 12 
Seleccione los componentes que desea instalar; en éste caso, seleccione instalar todos los 
componentes y pulse Siguiente. 
 
 13 
Seleccione el nombre de la instancia de SQL Server 2005 Express (por defecto 
SQLExpress), y pulse Siguiente. 
 
 14 
Seleccione el nombre de la cuenta que arrancará el servidor de SQL Server 2005 Express 
(Network Service por defecto), y habilite que el servicio de SQL Server se arranque al 
finalizar la instalación; a continuación pulse Siguiente. 
 
 15 
Seleccione el modo de autenticación (por defecto autenticación integrada de Windows), y 
pulse Siguiente. 
 
 16 
Seleccione el collation de la instancia de SQL Server. Como es una instalación nueva, y no 
se va a trabajar con bases de datos de versiones anteriores de SQL Server, se seleccionará 
Latin1_General, en caso de migraciones o posibilidad de trabajar con bases de datos 
importadas de SQL Server 2000 (o MSDE 2000), considere la opción por defecto (SQL 
Collations, Dictionary-order, case insensitive, for use with 1252 Character Set); a 
continuación pulse Siguiente. 
 
 17 
Seleccionar la opción de configuración de la instancia de SQL Server sobre la posibilidad de 
permitir a usuarios no-administradores de crear instancias. Por defecto habilitado; durante 
las siguientes lecciones se hablará de ello, habilítelo y pulse Siguiente. 
 
 18 
Opciones para informar a Microsoft sobre los errores no esperados sucedidos en la 
aplicación, y para enviar automáticamente información sobre las características usadas del 
producto; por defecto están deshabilitadas, pero se recomienda habilitarla para mejorar el 
producto enviando automáticamente información del uso que se hace del producto; a 
continuación se pulsa en Siguiente. 
 
 19 
Comienza el proceso de instalación informando de las características que se van instalando. 
 
 20 
Finalización del proceso de instalación con estado de casa funcionalidad instalada; en caso 
de haber algún error durante la instalación, aparecerán botones en color Rojo indicando el 
error; pulsando en la casilla correspondiente de la columna Status, podrá ver información 
del error producido; pulse Siguiente. 
 
 21 
Informe final de la instalación de SQL Server en el que se podrá ver todas las 
características instaladas, y un fichero de resumen con cada paso realizado durante la 
instalación. Pulse Finalizar, y ya está preparado para poder utilizar SQL Server 2005 
Express. 
 
 22 
1.1.3. Componentes instalados 
Para acceder a los componentes instalados en SQL Server 2005 Express, deberá hacer click en 
Inicio, Todos los Programas, Microsoft SQL Server 2005, Herramientas de 
configuración como ve en la siguiente imagen: 
 
 23 
Las opciones disponibles son las siguientes: 
1.1.3.1. Administrador de configuración 
Componente basado en Microsoft Management Console (MMC), con el que se puede 
administrar la configuración de los servicios SQL Server, protocolos de red utilizados, y 
configurar el cliente nativo de acceso a SQL Server. Es una herramienta que realiza todas 
las modificaciones haciendo uso de las nuevas APIs de administración SMO (sustituto de 
SQL-DMO). El hecho de usar tales APIs nos da la posibilidad de poder crear aplicaciones 
personalizadas para configurar el servidor; por ejemplo, se podría crear una aplicación 
basada en SMO que implemente o extienda las funcionalidades expuestas a través de la 
aplicación MMC. La aplicación tiene la siguiente apariencia: 
 
 24 
Al igual que desde el administrador de servicios del sistema operativo, se pueden cambiar 
las propiedades del servicio; la gran diferencia, es que mientras las llamadas de la 
aplicación MMC de los servicios realiza llamadas a las APIs del Kernel de Windows, el 
Administrador de Configuración, realiza las llamadas a través de las APIs de SMO. 
 
 25 
Se pueden configurar, habilitar o deshabilitar protocolos; configurar, o modificar puertos 
TCP/IP como se ve en la imagen: 
 
 26 
Así como establecer el orden de los protocolos de Red; en el siguiente ejemplo, están 
habilitados los protocolos Shared Memory, TCP/IP, y Named Pipes, mientras que el 
protocolo VIA está deshabilitado: 
 
Nota: Recuerde que la mayoría de estos cambios no tendrán efecto hasta que el servicio 
de SQL Server haya sido reiniciado. 
 27 
1.1.3.2. Informes de uso y errores de SQL Server 
La utilidad permite modificar las opciones de configuración relativas al feedback que se 
envía a Microsoft en cuanto al uso de las características del producto, e informe de errores 
no esperados. El nivel de detalle llega hasta el nivel de instancia, es decir, podemos decidir 
qué instancias envían información sobre los errores no esperados, o sobre el uso de las 
funcionalidades del producto: 
 
 28 
1.1.3.3. Configuración de superficie de SQL Server 
El aplicativo configuración de superficie de SQL Server es un asistente que ayuda a 
configurar cuales son las partes de SQL Server que se encuentran expuestas a 
interactuación desde el exterior. La filosofía del aplicativo es ayudar a configurar de manera 
sencilla y rápida los puntos de acceso al servidor. El aplicativo expone al usuario 
funcionalidades tales como configuración de servicios, y configuración de características de 
SQL Server; por ejemplo, CLR habilitado o no, soporte HTTP habilitado o no, endpoints 
configurados en el servidor, etc. 
 
 29 
El aplicativo permite modificar la configuración del servicio de SQL Server. 
 
 30 
También permite configurar el tipo de conexiones permitida sobre el servidor. Por ejemplo, 
SQL Server 2005 Express permite por defecto sólo conexiones locales; esto quiere decir 
que no se pueden realizar conexiones desde equipos externos a menos que se configure de 
servidor para permitirlo. Desde la aplicación, se podrá habilitar la posibilidad de conexiones 
de equipos remotos, y los protocolos de conexión permitidos. 
 
En cuanto a las opciones de configuración de funcionalidades del motor de base de datos, 
se incluyen: 
• Posibilidad de habilitar o deshabilitar la ejecución de consultas con OPENROWSET y 
OPENDATASOURCE: lo que estas funciones permiten es realizar consultas a servidores 
remotos (servidores expuestos a través de un origen de datos del que se provea drivers 
de acceso como ODBC, OLEDB, etc.) sin la necesidad de tener que crear un servidor 
vinculado. 
• Habilitar el soporte del CLR: creación de objetos de base de datos con cualquier 
lenguaje.NET Framework. 
• Habilitar el soporte nativo de Servicios Web: opción sólo disponible en la versión 
Enterprise de SQL Server 2005 que permite exponer SQL Server 2005 sin necesidad de 
implementar Servicios Web expuestos por IIS. 
• Habilitar el uso de Automatización OLE con sentencias T-SQL: posibilidad de realizar 
llamadas a objetos COM desde Transact-SQL con los procedimientos almacenados de 
 31 
sistema sp_OACreate, sp_OAGetProperty, sp_OASetProperty, sp_OAMethod, 
sp_OAStop, y sp_OADestroy. Automatización OLE entrará en desuso debido a la 
integración del CLR y su consiguiente facilidad para implementarlo mediante .NET 
Framework en lugar de objetos COM. 
• Habilitar el uso del procedimiento almacenado de sistema xp_cmdshell que permite 
ejecutar comandos de sistema en el servidor (tales como DIR, DELETE, COPY, etc.) 
• Habilitar el uso de endpoints de Service Broker. 
 
1.1.3.4. SQLCMD 
SQL Server 2005 Express no incluye la herramienta SQL Server Management Studio como 
el resto de versiones de SQL Server 2005. Para poder conectarse a SQL Server, el producto 
incluye una utilidad de línea de comando que permite conectarse a una instancia de SQL 
Server y realizar operaciones de manera similar a las herramientas gráficas. 
Evidentemente, la funcionalidad que nos proveen Management Studio no puede ser 
alcanzada con la utilidad de línea de comando, pero si provee lo necesario para conectarse 
e interactuar con la instancia. Típicamente esta utilidad suele ser utilizada para realizar 
tareas administrativas básicas. Por ejemplo, un ISV que desarrolla una aplicación y 
necesita ejecutar un script contra la instancia de SQL Server; imagínese que el ISV no ha 
desarrollado sus propias herramientas para ejecutar consultas ad-hoc contra el servidor; en 
este caso, puede utilizar SQLCMD para conectarse a la instancia de SQL Server y ejecutar 
el script deseado. Incluso, el ISV tiene la posibilidad de crear el script con SQL Server 
 32 
Management Studio en sus equipos de desarrollo porque Management Studio incorpora la 
posibilidad de ejecutar scripts en modo SQLCMD. 
La documentación del SQLCMD la puede encontrar en los Libros en Pantalla en "SQL Server 
2005 Express Edition", "Working with SQL Server Express", "Using the sqlcmd Utility (SQL 
Server Express)". 
La funcionalidad más novedosa implementada en SQLCMD es la posibilidad de utilizar 
variables a la hora de ejecutar scripts; por ejemplo: 
Dado el siguiente script llamado copia.sql: 
BACKUP DATABASE $(db) TO DISK = "$(path)\$(db).bak" WITH INIT 
donde $(db) es una variable que referenciará a un nombre de base de datos, y $(path) la 
ruta donde se guardará la copia. 
Si se ejecuta desde línea de comando 
SQLCMD -ic:\copia.sql -vdb="AdventureWorks" path="c :\data" 
lo que SQLCMD ejecutará será: 
BACKUP DATABASE AdventureWorks TO DISK = " c:\data\AdventureWorks.bak " 
WITH INIT 
lo cual quería decir que con un script de copia de seguridad, se podrían reutilizar con 
bastante facilidad distintas estrategias de copia de seguridad. Esto está muy bien, pero se 
limita la capacidad a la instancia en uso. Sin embargo, SQLCMD también permite cambiar 
de conexión tras haber conectado a un servidor con la palabra clave :connect; por ejemplo: 
desde línea de comando, se conecta a una instancia de la siguiente manera: 
SQLCMD -E -S(local)\SQLEXPRESS 
A continuación aparece el prompt, y puede ejecutar lo siguiente: 
:connect (local)\SQLEXPRESS_2 
que conectaría a una segunda instancia de SQL Server 2005. Otras opciones disponibles 
son :r para ejecutar un script, y :setvar para definir variables, por lo que el ejemplo 
anterior del backup se podría ejecutar de la siguiente forma: 
SQLCMD -E -S(local)\SQLEXPRESS 
:setvar db AdventureWorks 
:setvar path c:\data 
:r c:\copia.sql 
GO 
1.1.4. Componentes opcionales 
Las bases de datos de ejemplo y el código de ejemplo son un buen comienzo para conocer las 
nuevas funcionalidades del producto. La base de datos AdventureWorks se ha creado para 
sustituir a las anteriores Northwind, y Pubs que pecaban de ser bases de datos poco reales en 
cuanto a volumen de datos. Se ha tenido más cuidado en el diseño relacional de la base de 
datos AdventureWorks, y se ha aprovechado para incluir nuevas funcionalidades como soporte 
XML, novedades Transact-SQL, nuevos tipos de datos, etc. 
La otra fuente de conocimiento a mencionar son los Libros en Pantalla (BOL): la versión 
incluida en SQL Server 2005 Express es una versión "reducida" de la versión completa, pero 
en todo momento, da acceso a la Web de Microsoft para acceder a documentación y ayuda 
incluida en la versión completa de los Libros en Pantalla. A su vez, los Libros en Pantalla, 
incluyen la posibilidad de acceder directamente a los grupos de noticias para obtener 
 33 
respuesta a casos concretos, y también realizar búsquedas en sitios de la comunidad como 
CodeZone, ElGuille.info, GotDotNet.com, SSUG.com, SQLIS.com, etc. 
1.2. Integración con versiones Express 
En esta lección, conocerá cómo se integran la versión Express de SQL Server con Visual Studio, y 
cómo ayuda la versión Express de SQL Server en el proceso de despliegue de aplicaciones de 
bases de datos. Se le introducirá a nuevos conceptos como instancias de nombre para no-
administradores, y se le enseñará a desplegar aplicaciones de bases de datos con la versión 
Express de SQL Server 2005. 
Uno de los objetivos de la versión Express de SQL Server 2005, es simplificar el proceso de 
despliegue de aplicaciones de bases de datos; a diferencia del resto de versiones de SQL Server 
(Workgroup, Standard, Enterprise) en el que las bases de datos se cambian de lugar poco o casi 
nunca, la versión Express está pensada para aplicaciones de bases de datos que requieren en 
cierto modo que los ficheros de base de datos sean dinámicos. Esta movilidad de los ficheros se 
consigue durante la fase de despliegue. 
¿En qué ayuda al despliegue la versión Express? Los Vendedores de Software Independientes 
(ISV’s) generalmente desarrollan aplicaciones comerciales que requieren de un instalable, y a su 
vez requieren instalar una base de datos; La versión Express viene a solucionar los problemas que 
surgían en el proceso de instalación en este tipo de aplicaciones. 
1.2.1. Compatibilidad con versiones "mayores" de SQL Server 
La versión Express de SQL Server se pone en la línea de las versiones MSDE de anteriores 
versiones de SQL Server; esto quiere decir que una base de datos de SQL Server 2005 para la 
versión Express, es totalmente compatible con el resto de versiones de SQL Server 
(Workgroup, Standard, Enterprise). El proceso de migración entre versiones es tan sencillo 
como hacer una restauración de la copia de seguridad de la base de datos (comando 
RESTORE, o usando las herramientas gráficas), o usando la opción de adjuntar bases de datos 
(comando sp_attach_db, o con las herramientas gráficas). 
1.2.2. Instancias de nombre para usuarios no-administradores 
Uno de los problemas que tienen los ISVs que distribuyen aplicaciones con MSDE es que el 
usuario que realiza la instalación de la aplicación debe pertenecer al rol de administradores de 
SQL Server. Este es un requisito que en la versión Express de SQL Server 2005 se elimina con 
la aparición de las instancias de usuario. 
El objetivo de las instancias de usuario, es acercar a SQL Server al concepto de base de datos 
de escritorio; es una base de datos que sólo admite conexiones locales a través del protocolo 
de red "named pipes", no se pueden realizar conexiones a través de la red. El concepto de las 
instancias de usuario es similar al modelo de las bases de datos Access: una vez conectado al 
fichero de base de datos, el usuario tiene derechos administrativos sobre la base de datos, sin 
necesidad de la intervención de un usuario administrador. 
1.2.2.1. ¿Cómo funciona? 
En primer lugar, para habilitar el uso de instancias de usuario, en la cadena de conexión de 
la aplicación cliente deberásañadir la cadena "User Instance=true". De esta forma se 
indica a SQL Server Express, que la conexión se realizará sobre una instancia de usuario. 
En caso de que no existiera la instancia de usuario, SQL Server automáticamente, creará la 
instancia de usuario; consiste en crear una nueva instancia de SQL Server para el usuario 
requerido, en el que: 
• Se copiarán las bases de datos de sistema de la instancia por defecto de SQL Server 
2005 Express, y 
 34 
• Se iniciará otra "copia" del servicio de SQL Server Express; el nombre de la instancia es 
un valor aleatorio, por ejemplo (2E67C75A-1693-4D), y se debe considerar a la nueva 
instancia hija de la instancia principal de SQL Server Express. 
Nota: Conectándose a la instancia \SQLEXPRESS, con la vista sys.dm_os_child_instances 
se pueden consultar cuales son las instancias de usuario activas. 
La diferencia fundamental con las instancias tradicionales es que a la instancia de 
usuario solamente puede conectar el usuario para el que se ha creado la instancia. 
Además, por diseño, sólo se puede conectar mediante canalización por nombres, y no se 
puede conectar a la instancia de forma remota. 
Después de crear o iniciar la instancia de SQL Server Express, automáticamente, el proceso 
de conexión se encargará de adjuntar la base de datos que se ha especificado en la cadena 
de conexión a la instancia recién creada. 
A su vez, cuando la aplicación cliente cierra conexión con la base de datos, la base de datos 
se "desadjunta" de la instancia de SQL Server. En realidad, SQL Server tiene configurado 
un tiempo de espera antes de desadjuntar la base de datos de la instancia porque en caso 
contrario, el proceso de adjuntar/ desadjuntar podría causar problemas de rendimiento en 
la aplicación. 
Un ejemplo de cadena de conexión que deberá usarse para trabajar con instancias de 
usuario podría ser el siguiente: 
conn string = 
"Data Source=.\\SQLExpress;" + 
"Integrated Security=true;" + 
"attachdbfilename=|DataDirectory|\\mi_bd.mdf;" + 
"User Instance=true;" 
En .NET 2.0, aparece la palabra clave |DataDirectory|, que representa un path relativo a 
la instalación de la aplicación; por ejemplo, distribuimos una aplicación que admite 
personalizar la ruta de instalación, con |DataDirectory| podemos especificar rutas relativas. 
A su vez, también se puede especificar el valor de DataDirectory de la siguiente manera: 
AppDomain.CurrentDomain.setData(“DataDirectory”,”C: \ruta_por_defecto\”); 
1.2.3. Consideraciones 
• Como la instancia de usuario es hija de la instancia SQLEXPRESS, si la instancia 
SQLEXPRESS no está arrancada, la instancia de usuario no arrancará. 
• Un usuario sólo puede tener una instancia de usuario. 
• Las bases de datos de la instancia de usuario se crean en la ruta: \Documents and 
Settings\nombre_usuario\Local Settings\Application Data\Microsoft\Microsoft SQL 
Server Data\SQLEXPRESS 
• La réplica se deshabilita. 
• La instancia de usuario no admite Autenticación de SQL Server. Sólo se admite la 
Autenticación de Windows. 
• La compatibilidad de protocolo de red con las instancias de usuario sólo es posible 
mediante canalizaciones con nombre locales. 
• La instancia de usuario comparte las entradas de registro de la instancia primaria. 
• No se admiten instancias de usuario con código nativo. Esta característica sólo se 
admite con ADO .NET. 
 35 
1.2.4. Despliegue de la aplicación 
El objetivo principal de las instancias de usuario, es disponer de un fichero de base de datos, 
que se utiliza en una instancia cuando el usuario necesita acceder a la base de datos. Cuando 
no se está usando, la base de datos se desadjunta. ¿Qué se consigue con esto? Acercar la base 
de datos al concepto de base de datos de escritorio (como si fuera Access). De esta forma, el 
despliegue de la aplicación relacionada con la base de datos consistirá en: 
• Copiar los binarios de la aplicación. 
• Copiar el fichero de base de datos. 
Nota. Fíjate que sólo hay que copiar el fichero de base de datos; no se necesita adjuntar la 
base de datos a ninguna instancia de SQL Server, porque la propia aplicación se encarga de 
hacerlo por nosotros. 
Por lo tanto, para desplegar la aplicación deberemos incluir en la distribución la copia de la 
base de datos de la aplicación. Para ello lo podremos hacer de dos formas: 
• Usar el concepto de XCOPY copiando el contenido del directorio \bin\release de la 
aplicación generada en el directorio destino. 
• Usar la nueva tecnología ClickOnce, cuyo objetivo es facilitar el despliegue de la aplicación, 
y a su vez, gestionar las actualizaciones; en el proceso de instalación, además de la 
realizar la propia instalación, se podrá configurar la aplicación para actualizar 
automáticamente la aplicación cuando existan nuevas versiones. 
1.3. Acceso a datos 
Sin lugar a dudas uno de los ámbitos más importantes de un lenguaje o entorno de programación 
es su capacidad de acceso a datos. Prácticamente todas las aplicaciones conllevan la realización 
de accesos a datos. 
Le gustará saber que la plataforma .NET, y por lo tanto ASP.NET, ofrecen un potente modelo de 
acceso a fuentes de datos. Se le conoce con el nombre genérico de ADO.NET. 
Nota: No se deje engañar por el nombre: ADO.NET no tiene casi nada que ver con el anterior 
ADO utilizado en los tiempos de ActiveX y COM. Sí, dispone de conexiones, comandos e incluso 
una clase que recuerda a los Recordset, pero créame cuando le digo que es mejor que se olvide 
para siempre de todos ellos. Tanto la filosofía de trabajo como la tecnología son diferentes por 
completo y es mejor que utilice una estrategia de "ojos limpios" para acercarse correctamente a la 
nueva tecnología. 
Los conocimientos adquiridos en este módulo le servirán para cualquier tipo de desarrollo con 
.NET, no sólo para aplicaciones Web. Los conceptos explicados son válidos también para cualquier 
versión de .NET no sólo para la 2.0. 
1.3.1. Introducción a ADO.NET 
Como cualquier otro modelo de acceso a datos, ADO.NET es un conjunto de clases 
relacionadas entre sí que están especializadas en ofrecer toda la funcionalidad que un 
programador necesita para realizar acceso a datos y manejarlos una vez los ha obtenido. 
Las clases genéricas expuestas por ADO.NET se encuentran bajo el espacio de nombres 
System.Data. Este espacio de nombres define clases genéricas de acceso a datos que 
posteriormente son extendidas para ofrecer características y funciones específicas de cada 
proveedor. 
El objeto más importante a la hora de trabajar con el nuevo modelo de acceso a datos es el 
DataSet. Sin exagerar demasiado podríamos calificarlo casi como un motor de datos 
 36 
relacionales en memoria. Aunque hay quien lo asimila a los clásicos Recordsets su 
funcionalidad va mucho más allá como se verá en breve. 
1.3.1.1. Arquitectura de ADO.NET 
El concepto más importante que hay que tener claro sobre ADO.NET es su modo de 
funcionar, que se revela claramente al analizar su arquitectura: 
 
Figura 4.1.- Arquitectura de ADO.NET 
Existen dos capas fundamentales dentro de su arquitectura: la capa conectada y la 
desconectada 
1.3.1.2. La capa conectada 
La capa conectada de ADO.NET contiene objetos especializados en la conexión con los 
orígenes de datos. Así, la clase genérica Connection se utiliza para establecer conexiones 
a los orígenes de datos. La clase Command se encarga de enviar comandos de toda índole 
al origen de datos. Por fin la clase DataReader está especializada en leer los resultados de 
los comandos. 
La clase DataAdapter hace uso de las tres anteriores para actuar de puente entre la capa 
conectada y la desconectada como veremos después. 
Estas clases son abstractas, es decir, no tienen una implementación real de la que se 
pueda hacer uso directamente. Es en este punto en donde entran en juego los 
proveedores de datos. Cada origen de datos tiene un modo especial de comunicarse con 
los programas que los utilizan, además de otras particularidades quese deben contemplar. 
Un proveedor de datos de ADO.NET es una implementación concreta de las clases 
conectadas abstractas que hemos visto, que hereda de éstas y que tiene en cuenta ya 
todas las particularidades del origen de datos en cuestión. 
Así, por ejemplo, las clases específicas para acceder a SQL Server se llaman 
SqlConnection, SqlCommand, SqlDataReader y SqlDataAdapter y se encuentran bajo 
el espacio de nombres System.Data.SqlClient. Es decir, al contrario que en ADO clásico 
no hay una única clase Connection o Command que se use en cada caso, si no que existen 
 37 
clases especializadas para conectarse y recuperar información de cada tipo de origen de 
datos. 
Nota: El hecho de utilizar clases concretas para acceso a las fuentes de datos no significa 
que no sea posible escribir código independiente del origen de datos. Todo lo contrario. La 
plataforma .NET ofrece facilidades de escritura de código genérico basadas en el uso de 
herencia e implementación de interfaces. De hecho la versión 2.0 de .NET ofrece grandes 
novedades específicamente en este ámbito. 
Existen proveedores nativos, que son los que se comunican directamente con el origen 
de datos (por ejemplo el de SQL Server o el de Oracle), y proveedores "puente", que se 
utilizan para acceder a través de ODBC u OLEDB cuando no existe un proveedor nativo 
para un determinado origen de datos. 
Nota: Estos proveedores puente, si bien muy útiles en determinadas circunstancias, 
ofrecen un rendimiento menor debido a la capa intermedia que están utilizando (ODBC u 
OLEDB). Un programador novel puede sentir la tentación de utilizar siempre el proveedor 
puente para OLEDB y así escribir código compatible con diversos gestores de datos de 
forma muy sencilla. Se trata de un error y siempre que sea posible es mejor utilizar un 
proveedor nativo. 
La plataforma .NET proporciona "de serie" los siguientes proveedores de acceso a datos. 
Proveedor Espacio de nombres Descripción 
ODBC .NET Data 
Provider System.Data.Odbc 
Permite conectar nuestras 
aplicaciones a fuentes de datos a 
través de ODBC. 
OLE DB .NET Data 
Provider System.Data.OleDb 
Realiza la conexión utilizando un 
proveedor OLEDB, al igual que el 
ADO clásico. 
Oracle Client .NET 
Data Provider System.Data.OracleClient 
Proveedor de datos para acceder a 
Oracle. 
SQL Server .NET 
Data Provider System.Data.SqlClient 
Permite la conexión optimizada a 
SQL Server 7.0 o posterior, 
incluyenbdo la última versión SQL 
Server 2005. 
Los proveedores de acceso a datos que distribuye Microsoft en ADO.NET y algunos 
desarrollados por otras empresas o terceros, contienen los mismos objetos, aunque los 
nombres de éstos, sus propiedades y métodos, pueden ser diferentes. 
Existen, por supuesto, proveedores para tipos de orígenes de datos de cualquier gestor de 
datos existente en el mercado. Éstos los desarrolla normalmente la empresa responsable 
del producto. Si bien éstos optimizan el acceso a estos orígenes de datos nosotros siempre 
podremos realizarlo mediante ODBC u OLEDB si tenemos necesidad. 
En resumen: con la capa conectada de ADO.NET realizamos la conexión y comunicación 
con los orígenes de datos. Cada proveedor de datos implementa su propia versión de las 
clases Connection, Command, DataReader y DataAdapter (entre otras). 
• Las clases derivadas de Connection se utilizan para realizar la conexión y enviar y 
recibir información. 
• Las clases derivadas de Command permiten ejecutar sentencias SQL y procedimientos 
almacenados en el gestor de datos. 
 38 
• Las clases derivadas de DataReader se emplean para obtener los posibles resultados de 
un comando utilizando para ello el conducto de comunicación establecido por 
Connection. 
1.3.1.3. La capa desconectada 
Una vez que ya se han recuperado los datos desde un origen de datos la conexión a éste ya 
no es necesaria. Sin embargo sigue siendo necesario trabajar con los datos obtenidos de 
una manera flexible. Es aquí cuando la capa de datos desconectada entra en juego. 
Además, en muchas ocasiones es necesario tratar con datos que no han sido obtenidos 
desde un origen de datos relacional con el que se requiera una conexión. A veces 
únicamente necesitamos un almacén de datos temporal pero que ofrezca características 
avanzadas de gestión y acceso a la información. 
Por otra parte las conexiones con las bases de datos son uno de los recursos más escasos 
con los que contamos al desarrollar. Su mala utilización es la causa más frecuente de 
cuellos de botella en las aplicaciones y de que éstas no escalen como es debido. Esta 
afirmación es especialmente importante en las aplicaciones Web en las que se pueden 
recibir muchas solicitudes simultáneas de cualquier parte del mundo. 
Finalmente otro motivo por el que es importante el uso de los datos desconectado de su 
origen es la transferencia de información entre capas de una aplicación. Éstas 
pueden encontrarse distribuidas por diferentes equipos, e incluso en diferentes lugares del 
mundo gracias a Internet. Por ello es necesario disponer de algún modo genérico y 
eficiente de poder transportar los datos entre diferentes lugares, utilizarlos en cualquiera 
de ellos y posteriormente tener la capacidad de conciliar los cambios realizados sobre ellos 
con el origen de datos del que proceden. Todo esto y mucho más es lo que nos otorga el 
uso de los objetos DataSet, núcleo central de la capa desconectada de ADO.NET. 
Nota: Otra interesante característica de los DataSet es que permiten gestionar 
simultáneamente diversas tablas (relaciones) de datos, cada una de un origen diferente si 
es necesario, teniendo en cuenta las restricciones y las relaciones existentes entre ellas. 
Los DataSet, como cualquier otra clase no sellada de .NET, se pueden extender mediante 
herencia. Ello facilita una técnica avanzada que consiste en crear tipos nuevos de DataSet 
especializados en la gestión de una información concreta (por ejemplo un conjunto de 
tablas relacionadas). Estas nuevas tipos clases se denominan genéricamente DataSet 
Tipados, y permiten el acceso mucho más cómodo a los datos que representan, 
verificando reglas de negocio, y validaciones de tipos de datos más estrictas. 
Los objetos DataSet no dependen de proveedor de datos alguno y su funcionamiento es 
independiente de cómo hayan sido obtenidos los datos que contienen. Este es el concepto 
más importante que debemos recordar. 
El proceso general de trabajo de ADO.NET para acceder a un gestor de datos (SQL Server, 
por ejemplo) es casi siempre el mismo: se abre una conexión (clase Connection), se lanza 
una consulta SQL o procedimiento almacenado mediante un objeto de la clase Command, y 
se almacenan en memoria los resultados dentro de un objeto DataSet, cerrando la 
conexión. 
Nota: Aunque este es el comportamiento habitual de una aplicación de datos existen casos 
en los que no es recomendable almacenar en memoria (en un DataSet) todos los 
resultados de una consulta, bien por ser muchos registros o por contener datos muy 
grandes. En este tipo de casos se puede usar u objeto DataReader directamente para leer 
la información, tratarla y no almacenarla en lugar alguno. De todos modos lo más frecuente 
es realizar el proceso descrito. 
 39 
1.3.1.3.1. Unión entre capa conectada y desconectada 
La clase DataAdapter se ha incluido anteriormente en la capa conectada por que está 
implementada por cada proveedor de un modo diferente. En realidad es una clase que 
pone sus pies en ambos mundos (conectado y sin conexión) y sirve de nexo entre ellos. 
Un DataAdapter sabe como manejar correctamente los objetos proporcionados por su 
proveedor específico (fundamentalmente los vistos: Connection, Command y 
DataReader) y proporciona métodos para trasegar información desde el servidor a 
DataSets desconectados y viceversa haciendo uso de dichos objetos específicos del 
proveedor. 
Así, por ejemplo, el método Fill de un DataSet se utiliza para introducir los resultados 
de una consulta dentrode un DataSet para luego trabajar con ellos sin preocuparnos de 
su origen. Del mismo modo su método Update se utiliza para conciliar 
automáticamente con el origen de datos los datos modificados en un DataSet mientras 
no había conexión. 
1.3.1.3.2. Otras clases dependientes de DataSet 
Como hemos dicho antes un DataSet podría asimilarse a un pequeño gestor de datos en 
memoria. Como tal un DataSet permite mantener diversas tablas así como las 
relaciones entre ellas, incluso forzando que se cumplan restricciones de creación y 
actualización, como en una base de datos "real". Para ello se apoya en el uso de otras 
clases especializadas que son las siguientes: 
• DataTable: representa una tabla o relación de datos. Se puede asimilar a una tabla 
de un gestor de datos. Los datos obtenidos de una consulta de tipo SELECT de SQL 
se almacenan en un objeto de esta clase. 
• DataColumn: ofrece información sobre cada uno de los campos de los registros 
almacenados en un DataTable, como su nombre o su tipo. 
• DataRow: representa un registro de la tabla virtual definida por el DataTable. 
Contiene tantos elementos como campos tiene la tabla, cada uno del tipo definido 
por el objeto DataColumn correspondiente. 
• Constraint: las clases Constraint se emplean para definir restricciones en los tipos 
de datos contenidos en un DataTable. Por ejemplo se puede usar un objeto de esta 
clase para indicar que un determinado campo debe ser único o que se trata de una 
clave externa que debe ser tenida en cuenta en actualizaciones o borrados en 
cascada. 
• DataRelations: define la relación existente entre dos objetos DataTable. 
Normalmente se suelen utilizar un identificador común a ambas tablas aunque 
pueden ser combinaciones de más de uno de ellos. De este modo se sabe cómo 
obtener información de una tabla a partir de información en otra. Por ejemplo el 
identificador de una factura (su número, por ejemplo) puede servir para relacionar 
su registro con los registros de detalle de factura que están contenidos en otra tabla. 
• DataView: representa una vista concreta de un DataTable. Normalmente se trata 
de ordenaciones o filtros sobre los datos originales. Todas las tablas disponen de 
una vista por defecto (propiedad DefaultView) que ofrece los datos tal y como se 
han introducido en ésta y es la vista que se usa habitualmente. 
1.3.1.4. Vinculación de datos a controles Web 
Otra característica fundamental de ASP.NET que lo convierte en una herramienta ventajosa 
para el desarrollo de aplicaciones Web es la capacidad de vincular datos a controles Web. 
 40 
La mayor parte de los controles que podemos arrastrar sobre una página ASPX se pueden 
vincular a los objetos DataSet, DataTable y DataReader o a informaciones concretas 
contenidas en éstos. 
Ello facilita mucho el trabajo con datos desde la interfaz de usuario ya que no hay que 
molestarse en generar tablas con ellos, escribir JavaScript o proporcionar complejos medios 
propios para permitir su edición o navegación si hacemos un uso adecuado de la 
vinculación y los controles disponibles. 
Todo ello, gracias a ASP.NET y Visual Studio, equipara en muchos aspectos el desarrollo 
Web al clásico desarrollo de aplicaciones de escritorio donde este tipo de facilidades han 
estado disponibles desde hace años. Sin embargo en una aplicación Web donde no existe 
una conexión permanente disponible entre la visualización (navegador) y el lugar en el que 
se ejecuta el código no es algo fácil de conseguir. El uso de un modelo consistente como 
ADO.NET (idéntico en Web, escritorio y otros entornos) junto con las capacidades nativas 
de ASP.NET para abstraernos de estas dificultades (ViewState, Postback...) consiguen el 
"milagro". 
En este módulo veremos también lo sencillo que resulta crear interfaces para explotar los 
datos desde una página Web. 
1.3.2. Acceso a datos manual 
Tras haber aprendido un poco de teoría sobre ADO.NET a continuación explicaremos cómo se 
utilizan las clases de acceso datos para escribir código de acceso a datos de manera manual. 
Si bien es un tema algo árido y además en un gran porcentaje de los casos utilizaremos 
herramientas que nos faciliten la creación automática de código, es fundamental conocer la 
forma de trabajar sin ayuda para entender el funcionamiento real de los objetos de datos. 
1.3.2.1. Escritura manual de código 
En este apartado vamos a analizar cómo es el código necesario para recuperar y actualizar 
datos con ADO.NET. Posteriormente veremos como sacar partido a las facilidades del 
entorno de desarrollo Visual Studio 2005 para no tener que escribir el código a mano. Sin 
embargo es útil aprender a hacerlo de esta manera para entender bien su funcionamiento. 
1.3.2.1.1. Comandos de selección simples 
La mayor parte de las consultas que se lanzan contra una base de datos suelen 
utilizarse para obtener un conjunto de registros para tratar. Este tipo de consultas 
suelen ser expresiones SQL de tipo SELECT. El siguiente fragmento de código muestra 
los pasos necesarios para mostrar en una página los registros resultantes de una 
consulta: 
 41 
 
No se trata de un código optimizado (es más bien burdo) pero nos ayudará a entender 
perfectamente el proceso. Los datos los obtendremos de la conocida base de datos de 
ejemplo Northwind (que viene con todas las versiones de SQL Server). 
Nota: Para poder escribir código de acceso a datos en nuestro módulo debemos 
agregar referencias a los espacios de nombres que contienen las clases que vamos a 
utilizar. Para ello usamos las dos sentencias Imports siguientes: 
 
La primera de ellas agrega las clases genéricas de acceso a datos (como DataSet) y la 
siguiente las específicas de SQL Server. Si no lo hacemos recibiremos un error. 
Lo primero que se debe hacer es instanciar un objeto que represente la conexión a la 
base de datos. Dado que nos estamos conectando a SQL Server esta conexión será del 
tipo SqlConnection. Es lo que se hace en la primera línea del código anterior. La 
conexión debe realizarse con un servidor de datos y un esquema de datos concreto. 
Esto se indica mediante la cadena de conexión (al igual que se hacía en ADO 
tradicional). En este caso la cadena de conexión es la típica de SQL Server. Cada gestor 
de datos tiene la suya y hay que construirla de manera adecuada. El entorno de 
desarrollo Visual Studio 2005 nos ayuda a crearlas como veremos luego. 
Una vez creado el objeto con el que nos conectaremos hay que definir el comando a 
lanzar a la base de datos. Para ello se utiliza un objeto SqlCommand. Las propiedades 
básicas que hay que establecer para éste son la consulta que se lanzará (propiedad 
CommandText) y la conexión que se empleará para lanzarla (propiedad Connection) 
que es lo que se refleja en las líneas 6 y 7. 
Ahora que ya sabemos cómo nos conectaremos y qué queremos obtener debemos 
lanzar la consulta y recoger el resultado de alguna manera. 
La clase Command dispone de diversos métodos para ejecutar consultas: 
• ExecuteReader: este método lanza la consulta a la base de datos y devuelve una 
referencia a una instancia de la clase DataReader (SqlDataReader en el caso de SQL 
Server). Podemos utilizar el DataReader para recorrer los datos y procesarlos. 
 42 
• ExecuteNonQuery: ejecuta la consulta sin devolver resultado alguno. Simplemente 
envía la consulta al servidor y devuelve el número de registros afectados por ésta. 
Útil para realizar consultas de inserción (INSERT), actualización (UPDATE) y borrado 
(DELETE). 
• ExecuteScalar: lanza la consulta y devuelve un objeto con el valor del primer 
campo del primer registro que se obtenga de dicha consulta. Es útil para lanzar 
consultas de agregación como sumas (SUM), cuentas (SELECT COUNT * ....) y 
similares de las que sólo necesitamos un valor como resultado. 
En el ejemplo hemos utilizado el primer método ya que requerimos que devuelva varios 
registros con diferentes campos. Entonces lo que hacemos es (líneas a partir de la 9): 
1. Abrirla conexión. 
2. Crear una variable para contener una referencia a un objeto de la clase DataReader 
que es el que nos permitirá acceder a los resultados. Fíjese en que no se puede 
instanciar un DataReader (la declaración no lleva la palabra clave New). 
3. Se obtiene el resultado mediante el método ExecuteReader, recogiéndolo en la 
variable (dr) recién declarada. 
4. Se procesan los resultados (líneas 14-18). 
5. Se cierra la conexión. 
El objeto DataReader es asimilable a un cursor de servidor de sólo lectura y hacia 
adelante (conocidos como de manguera de bombero o firehose). Es decir, los datos 
devueltos por el DataReader sólo se pueden leer y no actualizar. Además de esto sólo 
se pueden leer en secuencia hacia adelante (no hay forma de regresar sobre lo 
andado). 
La propiedad HasRows nos indica si hay o no resultados devueltos. El método Read 
avanza una posición en los registros devolviendo True si quedan registros pendientes de 
leer. Con esta información es muy fácil entender las líneas 14 a 18. 
1.3.2.1.2. La cláusula Using 
¿Qué ocurre si se produce un error durante el procesamiento del bucle anterior en el 
que se trata el DataReader? La respuesta es que la conexión, que debemos tener 
abierta durante el procesamiento, no se cerrará pues el código no llega al final. 
Esto es algo muy grave ya que las conexiones que no se cierran no se pueden reutilizar 
y por lo tanto puede llegar un momento en que no tengamos conexiones disponibles, lo 
que limita enormemente la escalabilidad del sistema. 
Podemos evitar el problema escribiendo: 
 43 
 
De este modo, con la cláusula Finally nos aseguramos que siempre se va a cerrar la 
conexión. 
De todos modos escribir este código es algo tedioso sobre todo si queremos que la 
excepción se replique y sólo metemos la cláusula Finally por el hecho de cerrar la 
conexión. 
Para facilitar el trabajo VB.NET en .NET 2.0 incluye una cláusula especial denominada 
Using que habilita la destrucción automática de los objetos a los que se hace 
referencia. Así el código anterior quedaría simplemente: 
 
Al terminar la cláusula Using (aunque haya un error por medio) se llama de manera 
automática al método Dispose del objeto utilizado (en este caso una conexión). Entre 
otras cosas este método se encarga de cerrar el objeto si estaba abierto, por lo que no 
nos tendremos que preocupar de este aspecto. 
1.3.2.1.3. Grupos de registros 
Aunque los DataReader se asemejan al funcionamiento de un cursor firehose, en 
realidad difieren bastante de éstos. Imaginemos que conectamos con la base de datos 
en el ejemplo anterior y, mientras estamos procesando el bucle de los registros, se 
interrumpe la conexión a la base de datos por el motivo que sea. 
En principio en el caso de un cursor firehose tradicional obtendríamos un error porque 
se ha roto la conexión con el servidor. En el caso de un DataReader es posible que 
sigamos ejecutando varias vueltas más del bucle sin problemas. Esto se debe a que, en 
 44 
realidad, el DataReader obtiene los registros en grupos a través de la conexión y va 
solicitando nuevos grupos a medida que los necesita. 
Es algo que hay que tener en cuenta a la hora de utilizarlos. 
1.3.2.1.4. Ventajas e inconvenientes 
El código anterior, aunque sencillo, es un poco lioso y el uso de los DataReader está 
algo limitado dada su idiosincrasia (de sólo lectura y hacia adelante). Este código es 
adecuado si no necesitamos almacenar los resultados de la consulta en memoria ni 
regresar sobre ellos una vez procesados una primera vez. También es muy útil para 
obtener resultados con miles o millones de registros que queremos tratar 
secuencialmente pero no almacenar en memoria. 
Sin embargo para un uso cotidiano se trata de un código muy poco útil y complicado de 
utilizar salvo para cosas muy sencillas. Además sólo hemos utilizado clases de la capa 
conectada de ADO.NET. Todavía debemos aprender a obtener los resultados dentro de 
un DataSet para su explotación de manera cómoda. Hay que tender un puente entre 
ambos mundos (conectado y desconectado): el DataAdapter. 
1.3.2.2. DataAdapter: puente entre mundos 
Si lo que deseamos es poder almacena temporalmente en memoria los datos obtenidos de 
una consulta debemos recurrir al uso de objetos de la clase DataSet. Como sabemos se 
trata de un almacenamiento en memoria desvinculado por completo del origen de los 
datos. 
Si el ejemplo anterior lo modificamos para convertirlo en una función que nos devuelva un 
DataSet con los datos obtenidos a partir de la consulta, el resultado sería similar a este: 
 
La primera parte del código es como la anterior. Se crean una conexión y un comando. Lo 
que difiere bastante es la segunda parte. Hay varias diferencias importantes: 
1. Ya no aparece en el código objeto DataReader de tipo alguno. 
2. No se abre ni se cierra la conexión a la base de datos. 
3. Se crea un nuevo DataSet y aparece un objeto de la clase DataAdapter. 
 45 
Un DataAdapter es una clase que conoce las particularidades de la capa conectada de un 
determinado proveedor y es capaz de "comunicar" información entre ésta y la capa 
desconectada formada por los DataSet. 
El método Fill de un DataAdapter se encarga e rellenar un DataSet con los datos obtenidos 
a partir de una consulta (o procedimiento almacenado) definida a través de un comando. 
Su propiedad SelectCommand se usa para indicar qué comando se utilizará para rellenar 
el DataSet. 
Internamente el método Fill emplea el objeto DataReader devuelto por ExecuteReader y 
rellena el DataSet con él por lo que sería factible crear un código equivalente. Sin embargo 
es muy cómodo y nos evita problemas y el tener que "reinventar la rueda" en cada 
proyecto. 
1.3.2.2.1. El objeto DataSet 
Los objetos DataSet contienen a su vez objetos DataTable que son los que contienen 
realmente los datos. Para acceder a las tablas de un DataSet se utiliza su colección 
Tables. Se puede acceder a las tablas por posición (números enteros) o por nombre si lo 
sabemos. 
En un ejemplo sencillo como el anterior (y por otro lado uno de los más comunes) se 
crea una única tabla en el DataSet de nombre "Table1" y posición 0. 
Las tablas contienen dos colecciones interesantes: 
• Columns: conjunto de objetos de tipo DataColumn que ofrecen información sobre 
los campos de la tabla (nombre, tipo, longitud...). 
• Rows: colección de objetos de la clase DataRow que contienen información concreta 
sobre cada campo de un registro de la base de datos. 
Con esta información resulta muy sencillo tratar los datos de una consulta. Podemos 
acceder directamente a cualquier registro de la tabla usando su posición en la colección 
de filas. Por ejemplo para acceder al quinto registro de una tabla basta con escribir: 
Dim dr As DataRow 
Dr = ds.Tables(0).Rows(4) 
(nótese que las colecciones comienzan a numerarse en 0, de ahí que el quinto registro 
tenga índice 4). 
Podemos acceder a cualquier campo del registro usando su posición o bien su nombre, 
así: 
ds.Tables(0).Rows(4)("CompanyName") 
que devolverá un objeto del tipo adecuado para el campo que representa (una cadena, 
un objeto de fecha, un booleano, etc...). 
Nota: Es muy sencillo definir objetos DataTable que dispongan de los campos que 
deseemos sin depender de origen alguno de datos. Emplee el método Add de la 
colección Columns para crear nuevos campos, algunos de los cuales pueden ser incluso 
derivados mediante una fórmula de los valores de otros. Esto permite definir 
estructuras de almacenamiento a medida en memoria sin preocuparnos de usar una 
base de datos para ello. 
1.3.2.2.2. Ventajas del uso de objetos DataSet 
Es posible cargar datos de varias tablas en un mismo DataSet, incluso aunque procedan 
de bases de datos diferentes, y relacionarlas en memoria. Es posible establecer 
relaciones entre ellas para mantener la consistencia, así como hacer un mantenimiento 
en memoria de los datos (altas, bajas y modificaciones). Posteriormente se puede46 
sincronizar el DataSet con el servidor usando un DataAdapter, realizando el proceso 
contrario al de obtención de datos. Luego lo veremos. 
La principal ventaja de un DataSet es que podemos almacenarlo en donde queramos 
(en una variable global, en caché, incluso a disco a una base de datos) para trabajar 
con él sin estar conectado a una base de datos. De hecho se pueden transferir DataSet 
completos entre diferentes máquinas o por Internet, trabajar con ellos en remoto, 
almacenarlos, recuperarlos y finalmente transferirlos en cualquier momento de nuevo al 
origen (enteros o sólo los cambios) para sincronizarlos. 
Es posible moverse con libertad entre los registros de una tabla y sus registros 
relacionados en otras tablas. Y sobre todo, se pueden vincular con elementos de la 
interfaz gráfica para mostrar los datos automáticamente. 
1.3.2.3. Consultas parametrizadas 
Las consultas simples como la que acabamos de utilizar en los ejemplos anteriores son muy 
raras. En la realidad las consultas son mucho más complejas, suelen intervenir varias 
tablas y dependen de diversos parámetros que le añaden condiciones. 
Por ejemplo, si en la base de datos Northwind queremos obtener sólo aquellos clientes de 
un país determinado. Podríamos escribir de nuevo la función DameClientes para que se 
pareciese a la siguiente: 
 
Esta función acepta un país como parámetro y lo único que hace es concatenar a la 
consulta una nueva condición que introduce el país. 
Esto, sin duda, funcionaría. Sin embargo presenta multitud de problemas seguramente no 
demasiado obvios para los programadores noveles. Los más importantes son los 
siguientes: 
1. Este código es vulnerable a problemas de seguridad provocados por ataques de 
inyección de SQL. Esto puede poner en peligro fácilmente nuestra aplicación e incluso 
todo nuestro sistema en casos graves. El estudio de esta problemática se sale del 
ámbito de este curso, pero créame cuando le digo que se trata de un gravísimo 
problema que debemos evitar a toda costa. 
 47 
2. Si se solicitan 100 consultas idénticas al servidor en las que sólo varía el nombre del 
país por el que se filtra, éste no tiene modo de saber que son las mismas y sacar factor 
común. Es decir, no se puede reutilizar el plan de consulta de la primera de ellas 
para las demás por lo que se debe calcular de nuevo cada vez, incidiendo en el 
rendimiento y la escalabilidad de la aplicación. Obviamente en consultas más 
complicadas es un problema más importante que en esta. 
3. Este código es más difícil de transportar a otros sistemas de bases de datos ya que hay 
que incluir los delimitadores y notaciones específicos de cada gestor. Por ejemplo en 
SQL Server los delimitadores de fechas son comillas simples ('), mientras que en Access 
son almohadillas (#) y la sentencia usada no se puede reutilizar. 
La forma correcta de realizar este tipo de consultas es utilizar parámetros en la consulta. 
Ello evita los problemas enumerados. 
Los objetos de tipo Command disponen de una colección llamada Parameters que sirve 
para asignar dichos parámetros. Éstos previamente se definen en la consulta utilizando 
comodines que marquen su ubicación. 
Nota: Cada proveedor de datos utiliza su propia convención para indicar la posición de los 
parámetros en una consulta. En el caso de SQL Server se indican con una arroba '@' 
seguida de un identificador. En otros proveedores no se puede definir nombre para los 
parámetros, sólo se marca su posición con un caracter especial. 
La función anterior empleando parámetros sería la siguiente: 
 
Se ha resaltado los cambios. 
Como vemos en lugar de concatenar cadenas se marca la posición de las partes de la 
consulta que varían con un parámetro que consta de una arroba seguida de un 
identificador. 
Luego hay que declarar el parámetro añadiéndolo a la colección de parámetros. Para ello se 
indica su nombre y el tipo de datos que representa (en este caso un NVarChar de SQL 
Server, que es una cadena de longitud variable). 
 48 
Por fin se asigna su valor concreto antes de lanzar la consulta. 
El proveedor de datos crea la consulta de la manera correcta, usando los delimitadores 
adecuados y tratando los datos del modo que sea preciso para asegurar que es correcta. 
Ello elimina los problemas de los que hablábamos anteriormente y permite optimizar el uso 
de consultas. 
1.3.2.4. Altas bajas y modificaciones 
Con lo que hemos visto hasta ahora ya estamos en condiciones de escribir código para 
realizar altas, bajas y modificaciones de registros. Al fin y al cabo éstas son simplemente 
consultas SQL del tipo adecuado (INSERT, DELETE o UPDATE) que se deben enviar al 
servidor. 
Así pues, para crear un nuevo cliente podemos escribir una función como la siguiente: 
 
Es un código muy similar al anterior que realizaba una selección de datos. En este caso se 
ha definido una consulta de inserción con tres parámetros. En lugar de usar ExecuteReader 
o un DataAdapter en este caso se utiliza el método ExecuteNonQuery. Éste lanza la 
consulta (es decir, se inserta el nuevo registro) y devuelve el número de registros 
afectados por la consulta (que en el caso de una inserción siempre es 1 si se inserta 
correctamente o 0 si ha habido un error). 
Las actualizaciones y eliminaciones de registros se podrían conseguir de modo similar. 
1.3.2.4.1. Trabajando desconectados 
El código anterior funciona perfectamente pero no es la forma óptima de trabajar 
cuando tenemos que tratar con datos desconectados contenidos en objetos DataSet. 
 49 
Los DataSet normalmente circulan, independientes de cualquier origen de datos, entre 
las diferentes capas de una aplicación e incluso se mueven entre contextos de ejecución 
y máquinas (por ejemplo a través de un servicio Web como veremos). Hemos dicho que 
son como pequeñas bases de datos, por lo que la forma habitual de trabajar con ellos es 
añadir, eliminar y modificar registros directamente sobre sus tablas, sin pensar en la 
ubicación real de estos datos. 
Así pues, para crear un nuevo registro en un DataSet debemos usar el método 
NewRow del DataTable en la que lo queremos insertar. El nuevo registro tiene la 
misma estructura (el mismo "esquema") que el resto de registros y sólo tendremos que 
rellenar sus datos. Una vez rellenados añadiremos el nuevo registro a la colección de 
filas de la tabla. Así por ejemplo si tenemos almacenado un DataSet con una tabla con 
los datos de los clientes obtenidos con la función de ejemplo DameClientes, podríamos 
agregar uno nuevo de la siguiente manera: 
 
Es decir, se crea la nueva fila/registro, se rellenan sus campos y se añade a la colección 
de filas con el método Add de ésta. 
La actualización de datos es más sencilla aún ya que basta con acceder directamente al 
registro que nos interesa modificar y cambiar los valores de sus campos. Por ejemplo, 
para modificar la dirección del cliente cuyos datos están en el quinto registro de nuestra 
tabla sólo hay que escribir: 
 
Por fin, para eliminar un registro sólo hay que usar su método Delete, así: 
 
que borraría el quinto registro de nuestra tabla en memoria. 
1.3.2.4.2. Conciliando los cambios con el origen 
Es muy fácil trabajar con los Dataset en memoria de este modo. Sólo hay un "pequeño" 
problema: los cambios se realizan en memoria pero, al no estar vinculado el DataSet 
con origen de datos alguno, no los veremos reflejados en la base de datos que es lo que 
buscamos. 
Debemos realizar una sincronización entre la representación en memoria de los datos y 
su ubicación física real, para lo cual debemos hacer que los cambios trasciendan a la 
capa conectada. Al igual que cuando los recuperamos, el trasiego en el otro sentido se 
realiza con la ayuda del puente que representa la clase DataAdapter. 
Al igual que utilizábamos la propiedad SelectCommand para indicar cómo se 
recuperaban los datos hacia un DataSet, ahora debemos utilizar las propiedades 
InsertCommand, UpdateCommand y DeleteCommand para indicarqué comandos 
se deben usar para agregar, modificar y eliminar los registros modificados en memoria 
a través del DataSet. 
Una vez especificados estos comandos sólo resta llamar al método Update del 
DataAdapter para que se ocupe de sincronizar automáticamente todos los cambios que 
hayamos realizado en las tablas en memoria. Este método acepta como argumentos un 
 50 
DataSet completo, una DataTable o incluso un DataRow si sólo queremos actualizar un 
único registro. 
1.3.2.4.3. Definición de los comandos 
Los comandos de inserción, modificación o borrado para el DataAdapter se definen del 
mismo modo que en el código de ejemplo al principio de este apartado, es decir, se 
define la consulta apropiada y sus parámetros. En esta ocasión como los parámetros 
serán rellenados automáticamente por el DataAdapter hay que utilizar una sobrecarga 
del método Add de la colección de parámetros que incluye el nombre del campo 
asociado con el parámetro, así: 
 
En este caso se define el parámetro "@Dirección", de tipo NVarChar y longitud 60 que 
se refiere siempre al valor del campo "Address" de la tabla. 
Por ejemplo, para definir la consulta de eliminación de registros de la tabla de clientes 
usaríamos el siguiente código: 
 
siendo CustomerID la clave primaria de la tabla. 
Una vez definidos los tres parámetros de alta, baja y modificación sólo resta llamar a 
Update para que el DataAdapter se ocupe de toda la sincronización. 
1.3.2.4.4. Ventajas 
Este modelo está lleno de ventajas aunque a primera vista pueda parecer algo 
engorroso. 
Nota: Luego veremos que podemos usar las herramientas que nos proporciona Visual 
Studio 2005 para definir de manera automática los comandos de manipulación de datos 
sin necesidad de pasar el trabajo de hacerlo manualmente. 
Para empezar podemos trabajar con los datos en total libertad sin preocuparnos de si 
existe conexión o no con el origen y aunque el DataSet se manipule en una ubicación 
física a miles de kilómetros del origen y desconectado de éste o los cambios se 
almacenen a disco y se concilien días más tarde. 
Se pueden realizar multitud de modificaciones en los datos y luego conciliarlas 
simultáneamente en lugar de hacerlo en tiempo real de una en una. 
El paso de datos entre capas y funciones se simplifica. Lo habitual antes era definir 
funciones con tantos parámetros como datos se quisieran modificar en un registro. Por 
ejemplo, para insertar un registro en una tabla que tiene 20 campos se definía una 
función con 20 parámetros (muchos de ellos opcionales) o, en el mejor de los casos, se 
pasaba una clase creada a medida que representaba lo valores del registro. Ahora basta 
con pasar un DataSet, un DataTable o un dataRow que ya contiene toda la información 
que necesitamos saber sobre los registros y su tabla asociada. 
Lo mejor es que es posible saber mediante ciertas propiedades qué registros han 
cambiado (nuevos, modificados, borrados) y mover entre capas exclusivamente estos. 
La propiedad HasChanges de los DataSet, DataTable y DataRow nos informa de si el 
objeto ha sufrido cambios de algún tipo. 
El método GetChanges de los objetos DataSet y DataTable devuelve un subconjunto 
de los datos que contiene exclusivamente los cambios. Así, aunque en un DataSet 
 51 
tengamos 1000 registros, si sólo hemos modificado 2 sólo será necesario trasegar la 
información de estos a la hora de enviarlos a otra capa o función para sincronizarlos con 
la base de datos. 
El método GetChanges se puede invocar sin parámetros o indicando qué tipo de 
cambios queremos obtener, lo que se indica con un valor de la enumeración 
DataRowState: 
Valor Significado 
Added Registros que no estaban originalmente 
Deleted Registros que se han eliminado 
Modified Registros cuyos valores se han modificado 
UnChanged Registros que no se han modificado 
Detached Registros que se han desasignado de una tabla (pero no borrado con 
Delete) 
Se puede dejar un DataSet en estado sin modificar llamando a su método 
AceptChanges. Esto es lo que hace un DataAdapter tras haber sincronizado los 
cambios con el origen de datos. 
1.3.3. Acceso a datos con Visual Studio 2005 
Ahora que ya hemos visto la forma de trabajo manual con ADO.NET y dominamos los 
fundamentos, vamos a sacar partido a todas las ventajas que nos proporciona un entorno 
como Visual Studio 2005 que, como veremos, nos permiten hacer casi cualquier tarea de datos 
sin necesidad de escribir código. 
1.3.3.1. Controles de datos 
Aparte de la escritura manual de código y el uso directo de objetos de ADO.NET, ASP.NET 
2.0 proporciona un nuevo modelo de trabajo declarativo para acceso a datos que nos 
permite realizar tareas comunes de acceso a datos sin escribir código alguno. 
ASP.NET 2.0 presenta dos nuevos tipos de controles Web que participan en este modelo 
declarativo de enlace a datos. Estos controles nos abstraen por completo de las 
complejidades de manejo de las clases de ADO.NET por un lado, y de las dificultades 
inherentes al modo de trabajo desconectado de las páginas Web. Equiparan en muchos 
aspectos el desarrollo Web al tradicional desarrollo de aplicaciones de escritorio. 
Estos controles se encuentran agrupados en el cuadro de herramientas bajo el nombre de 
"Datos", tal y como se ve en la figura. 
 52 
 
1.3.3.1.1. Orígenes de datos 
Estos controles de datos representan conexiones con diferentes tipos de orígenes de 
información que van desde bases de datos a objetos de negocio. No disponen de 
apariencia visual pero se arrastran igualmente sobre los formularios Web para trabajar 
con ellos visualmente y poder usar sus paneles de tareas. Abstraen al programador de 
las complejidades relacionadas con el manejo de los datos, permitiendo de manera 
automática seleccionarlos, actualizarlos, ordenarlos, paginarlos, etc. 
ASP.NET 2.0 ofrece los siguientes controles de origen de datos que se pueden ver en la 
figura anterior: 
Control Descripción 
SqlDataSource Enlaza con cualquier base de datos para que exista un 
proveedor de ADO.NET. 
AccessdataSource Esta especializado en trabajar con bases de datos Microsoft 
Access. 
ObjectDataSource Se enlaza con objetos de negocio y capas personalizadas de 
acceso a datos. 
XmlDataSource Trata datos contenidos en documentos XML. 
SiteMapDataSource Se enlaza con la jerarquía de clases expuesta por el modelo de 
navegación de sitios de ASP.NET 2.0. 
¡ATENCIÓN!: El control SqlDataSource sirve para enlazar con cualquier gestor de 
datos relacional para la que haya proveedor ADO.NET disponible, no sólo para enlazar 
con SQL Server. No se deje despistar por su nombre. 
1.3.3.1.2. Concurrencia optimista 
Durante la configuración de un origen de datos SQL (luego lo verá en el primer vídeo de 
esta lección) una de las opciones avanzadas que se presenta habla de la Concurrencia 
optimista. La concurrencia optimista evita la actualización de registros en el caso de 
que haya variado cualquiera de sus campos desde que se obtuvieron de la fuente de 
datos. Este comportamiento puede ser bueno en ciertas ocasiones, cuando queremos 
preservar los cambios realizados por cualquier usuario. En otras sin embargo no resulta 
de utilidad y sí añade una gran sobrecarga al acceso a datos. 
 53 
Se le denomina concurrencia optimista porque parte de la base de que la posibilidad de 
coincidencia de dos usuarios sobre el mismo registro es baja y es un caso que apenas 
se dará. Al caso contrario a la concurrencia optimista se le denomina concurrencia 
pesimista. 
Nota: En mi opinión debería llamarse "concurrencia realista" ya que, lo cierto es que si 
se analiza con detenimiento la posibilidad de conflicto en un sistema grande tiende a ser 
realmente pequeña en la mayoría de los casos. Y de todos modos el sobreescribir cierta 
información no suele ser un problema grave salvo cuando hablamos de cuestiones de 
dinero, facturas y similares. 
Cuando se establece la concurrencia optimista las consultas que genera el asistente de 
Visual Studioincluyen todos los campos del registro como condición de búsqueda del 
mismo, por ejemplo: 
DELETE FROM [Customers] 
WHERE [CustomerID] = @original_CustomerID 
AND [CompanyName] = @original_CompanyName 
AND [ContactName] = @original_ContactName 
AND [ContactTitle] = @original_ContactTitle 
AND [Address] = @original_Address 
AND [City] = @original_City 
AND [Region] = @original_Region 
AND [PostalCode] = @original_PostalCode 
AND [Country] = @original_Country 
AND [Phone] = @original_Phone 
AND [Fax] = @original_Fax 
mientras que en un caso de concurrencia pesimista se emplea simplemente la clave 
primaria del registro para localizarlo: 
DELETE FROM [Customers] WHERE [CustomerID] = @original_CustomerID 
Es decisión suya qué tipo de actualización utilizar pero en la mayor parte de los casos 
usará seguramente la pesimista que, de hecho, es la que usted utiliza normalmente si 
escribe las funciones a mano de manera independiente. 
1.3.3.1.3. Controles enlazados a datos 
Se trata de controles de interfaz de usuario que, haciendo uso de los anteriores, 
muestran la información a través de la página. Pueden sacar partido a todas las 
propiedades de los orígenes de datos y por lo tanto habilitan de manera sencilla la 
edición, eliminación, ordenación, filtrado y paginación de los datos entre otras cosas. 
Para conectar un control enlazado a un DataSource sólo hay que establecer su 
propiedad DataSourceID indicando el nombre apropiado. Así de fácil. 
Nota: Si usted ya conoce los controles enlazados a datos de ASP.NET 1.x como el 
DataGrid, el DataRepeater, etc... estos controles le resultarán más cómodos de utilizar 
pues al contrario que con aquellos no hay que escribir código alguno. Aunque estos 
controles "antiguos" no aparecen en el cuadro de herramientas siguen estando 
soportados y los puede seguir utilizando. Incluso si lo desea puede añadirlos al cuadro 
de herramientas. De todos modos se recomienda utilizar el nuevo modelo declarativo de 
acceso a datos. 
1.3.3.1.4. Uso de los controles de datos en la práctica 
La mejor forma de conocer la manera de trabajar con estos controles es viéndolos 
actuar en la práctica. Los vídeos de esta lección muestran un ejemplo completo de uso 
de los controles en el que se explotan unos datos para su visualización, edición y 
eliminación. Por favor, examínelo con atención y luego trate de practicarlo por su cuenta 
con ejemplos similares. 
 54 
1.3.3.2. DataSet tipados 
La clase DataSet, como cualquier otra clase no sellada de .NET, puede ser extendida 
mediante herencia para añadirle nuevas funcionalidades y aprovechar las ya existentes. Si 
creamos una nueva clase que herede de DataSet y ésta la especializamos en el tratamiento 
de un conjunto de datos determinado que conocemos de antemano nos encontramos un 
DataSet especializado. 
Por ejemplo, podemos crear un DataSet especial que tengan en cuenta las particularidades 
de los datos que maneja para validarlos antes de permitir su inserción, que verifique las 
relaciones con otros datos o que los transforme o controle el acceso a los mismos. Nosotros 
sólo tendríamos que ocuparnos de estas tareas dejando a la clase DataSet de la que hemos 
heredado todos los puntos complejos que tienen que ver con la gestión de datos pura y 
dura. 
Esta es, en esencia, la idea que subyace bajo los DataSet tipados de Visual Studio 2005. 
Se trata de clases especializadas derivadas de DataSet que ofrecen una forma más rápida y 
sencilla de acceder a los datos que albergan. Además Visual Studio nos permite crear este 
tipo de DataSet de forma visual y usando asistentes. En el vídeo se ilustra la manera de 
conseguirlo. 
Los DataSet tipados parten del conocimiento preciso de la estructura de una base de datos 
para definir su funcionalidad. Esta es su principal diferencia con los DataSet normales 
puesto que éstos son genéricos y no saben nada acerca de los datos que albergan. Los 
tipados sólo sirven para albergar una información muy concreta. Ganan en especialización 
y pierden en versatilidad. 
Para agregar un DataSet tipado a nuestro proyecto sólo hay que presionar con el botón 
secundario sobre la carpeta App_Code y en el diálogo que aparece elegir el icono de 
DataSet. La extensión del archivo generado es '.xsd' porque lo que en realidad albergan es 
un esquema XML que define la estructura de los datos en los que se van a especializar. 
Una vez agregado el DataSet aparece una superficie de diseño y un asistente como el de la 
figura. 
 
Figura 4.5.- Primer paso del asistente de configuración de un TableAdapter. 
 55 
Este asistente nos permite configurar un objeto TableAdapter que se encargará de 
trasegar datos entre el DataSet tipado que estamos creando y la base de datos. Un 
TableAdapter es una clase que encapsula a un DataAdapter especializado en los datos que 
vamos a procesar con la tabla del DataSet tipado que estamos definiendo. De hecho sus 
métodos son, por defecto, los mismos que los de un DataAdapter normal (Fill, Update...). 
Con él dispondremos de métodos para recuperar información, crear nuevos registros, 
actualizarlos y eliminarlos, sólo que los correspondientes comandos estarán creados de 
manera automática o asistiéndonos en ello. Así, por defecto, se definen un par de métodos 
para obtener los datos subyacentes rellenando un DataSet que se le pase (método Fill) o 
devolviendo directamente un DataTable (método GetData). Además el método Update 
sirve para conciliar automáticamente los cambios del un DataSet tipado con la base de 
datos original. 
No vamos a analizar desde el texto la definición de estos objetos adaptadores pero puede 
conocerlo viendo el vídeo de esta lección. 
Truco: Podemos ver el código que se genera de manera automática para crear el 
DataAdapter si hacemos doble-clic sobre él desde el examinador de objetos de Visual 
Studio (CTRL+ALT+J). Esto hará que se abra el archivo de código auto-generado por 
ASP.NET desde la ubicación real de ejecución (normalmente una ruta del estilo 
C:\Windows\Microsoft.NET\....). Es muy interesante echarle un vistazo a este código para 
aprender el funcionamiento interno de los DataSet tipados. 
1.3.3.2.1. Partes de un DataSet tipado 
Al igual que un DataSet normal, uno tipado consta de un conjunto de tablas y relaciones 
entre ellas. En este caso, sin embargo, podemos acceder a las tablas y a sus campos 
utilizando directamente sus nombres en lugar de recorrer la colección de tablas, lo cual 
lo hace más fácil de usar. 
Cada una de las tablas del DataSet lleva asociado como mínimo un TableAdapter. Entre 
los dos objetos (el DataTable y el o los TableAdapter relacionados) se reparten el 
trabajo. El DataTable tipado mantiene en memoria la información y el TableAdapter 
actúa de puente con la tabla real en la base de datos. 
Nota: Como sabemos (y veremos en el vídeo también) las tablas de un DataSet no 
tienen porqué coincidir con tablas reales de una base de datos ya que pueden ser 
resultados obtenidos de una consulta compleja que involucre a varias tablas. En estos 
casos es más complicada la actualización y se suelen usar únicamente para recuperar 
datos. la alternativa habitual es tratar de replicar la estructura física de la base de datos 
en la estructura en memoria del DataSet de modo que se tiene acceso estructurado a la 
misma información y gracias a las relaciones y restricciones se conserva la consistencia 
de los datos también estando desconectados. 
El DataSet tipado dispone de propiedades que coinciden con los nombres de los objetos 
que contienen. Así, por ejemplo, si tenemos una tabla "Clientes" con un campo 
"Nombre" podemos acceder a él directamente con este código: 
ds.Clientes(0).Nombre 
que nos daría el nombre del primer cliente de la tabla de clientes en el DataSet 'ds'. 
esta propiedad nombre además ya sería un campo de tipo String que es el tipo 
adecuado para la información albergada, por lo que se simplifica mucho su uso. 
En un DataSet normal para obtener lo mismo tendríamos que haber

Continuar navegando