Capítulo 4.

Programación en ADO
4.1. Las bases de datos relacionales (RDBMS)
Una base de datos relacional es un conjunto de tablas que mantienen
algún tipo de relación entre ellas. Una base de datos es un conjunto de
información que se organiza por mediación de una estructura lógica. La
información puede ser guardada en un fichero o en varios ficheros, también
conocidos como tablas.

4.1.1. Las Tablas

Dentro de la base de datos, las tablas son el objeto más básico e
importante. El rendimiento de la base de datos y por extensión de las
aplicaciones que accedan a ellas, dependen en gran medida del diseño de las
tablas. Una tabla es una matriz bidimensional, que contiene filas y columnas.
Las filas son los registros de la tabla y las columnas son los campos de la tabla.
A las filas también se les conoce con el nombre de tuplas o registros. Un
campo es una forma de decir que tipo de información contendrán las filas en
esa posición. Por ejemplo una columna llamada Nombre, podrá contener el
nombre de las personas.
Campos de la Tabla: Nombre, Apellidos y DNI
Estructura de la Tabla:

Nombre Apellidos DNI
Filas de la tabla o registros que contienen
Antonio Pérez López 7328714K los datos organizados por las columnas de
Luis Martínez Sánchez 3858582L la tabla, también llamadas campos.
María García Hernández 4738270X

Las tablas de datos se pueden relacionar entre sí, generando bases de
datos relacionales. En el mercado, existen varios sistemas administradores de
bases de datos relacionales, como son: Access, SQL Server, MySQL, Oracle,
SysBase, Informix, etc.

Una tabla suele ser la representación de clases de objetos físicos, como
por ejemplo, clientes, empleados, facturas, etc. Cada objeto físico, como un
empleado, tiene su registro correspondiente en la tabla.

En esta imagen podemos ver una tabla de empleados con 7 campos.

Capítulo 4. Programación en ADO. Página 1

En este caso el campo ID de la tabla, es el campo Clave de la tabla, lo
que significa que la tabla es accedida directamente por este campo y permite
identificar a ese registro de forma inequívoca sobre cualquier otro registro de la
tabla.

El campo clave, ID de la tabla Empleados, permite que esta tabla se
relacione con otras tablas de la base de datos, como por ejemplo Pedidos, o
Privilegios de Empleados.

4.1.2. Las Claves. Existen distintos tipos de clave:

Clave única. Cada tabla puede tener uno o más campos cuyos
valores identifican de forma única cada registro de dicha tabla, es
decir, no pueden existir dos o más registros diferentes cuyos
valores en dichos campos sean idénticos. Este conjunto de
campos se llama clave única. Pueden existir varias claves únicas
en una determinada tabla, y a cada una de éstas suele llamársele
candidata a clave primaria.
Clave primaria. Una clave primaria es una clave única elegida
entre todas las candidatas que define unívocamente a todos los
demás atributos de la tabla, para especificar los datos que serán
relacionados con las demás tablas. La forma de hacer esto es por
medio de claves foráneas. Sólo puede existir una clave primaria
por tabla y ningún campo de dicha clave puede contener valores
NULL.
Clave externa o foránea. Una clave externa es una referencia a
una clave en otra tabla. Las claves externas no necesitan ser
claves únicas en la tabla donde están y sí a donde están
referenciadas. Por ejemplo, el código de departamento puede ser
una clave externa en la tabla de empleados, obviamente se
permite que haya varios empleados en un mismo departamento,
pero existirá sólo un departamento.

El objetivo en el diseño de las tablas es evitar la redundancia de los
datos, es decir, imaginemos que la dirección del empleado apareciera en más
de una tabla como contenido de un campo. En ese caso, hablamos de
redundancia. La redundancia ralentiza la ejecución de la base de datos, así
como genera un exceso de espacio en disco que, con una buena planificación
en las relaciones entre tablas, se podría solucionar. La forma de evitarlo, es
crear por ejemplo una tabla con las direcciones de los empleados y usar un
campo clave para acceder a ellas.
A parte de la clave primaria, podemos definir claves secundarias, que
son claves que se utilizan para poder relacionar de una forma más precisa las
tablas. El hecho de hace coincidir una clave secundaria con un valor de clave
primaria, se denomina operación de búsqueda.

Capítulo 4. Programación en ADO. Página 2

Las claves primarias suelen ser campos numéricos de autoincremento,
llamados Autonuméricos en Access e Identify en SQL Server. El uso de valores
de campos alfabéticos como Clave Principal, ha caído en desuso por parte de
los diseñadores de bases de datos, debido a su lentitud a la hora de realizar
operaciones, pero muchas veces es la mejor o única opción. Otro método para
generar claves exclusivas es utilizar los identificadores globales exclusivos
(GUID). Los GUID son números binarios de 16 bytes cuya exclusividad está
garantizada local y universalmente; ningún otro ordenador del mundo puede
duplicar un GUID. En SQL Server, uniqueidentifier, es un tipo GUID.

Por mediación de las claves podemos crear relaciones que agilizan las
consultas y el acceso a los datos. Una tabla puede tener múltiples relaciones
con otras tablas. El tipo de relaciones posibles que se pueden implementar en
una base de datos son:

Uno a Varios. Representa una relación entre un solo valor de
clave principal (“uno”) y varias instancias del mismo valor en el
campo clave secundario (“varios”). Las relaciones uno a varios
son representadas como un 1 y el símbolo de infinito.
Uno a Uno. Son relaciones en las que se conectan los valores de
clave principal de dos tablas. Es una relación poco usada.
Varios a Varios. Son relaciones que requieren tres tablas, una de
las cuales es la tabla de vinculación. La tabla de vinculación debe
de tener dos claves secundarias, cada una con una relación
varios a uno con una clave principal de dos tablas relaciones.
Estas relaciones también se las conoce como indirectas.

Ejemplo de Esquema de las relaciones de una Base de Datos:

Capítulo 4. Programación en ADO. Página 3

Los índices se organizan en dos categorías: Agrupados. Sólo puede haber un índice agrupado por tabla. como inserciones. Capítulo 4. Un índice es un objeto que existe sólo dentro del marco de una determinada tabla o vista. se proporciona otra clave con la que podremos encontrar la información que estamos buscando. posteriormente. Este tipo de índice apunta a otro valor que nos va a permitir encontrar el dato. cada elemento tiene sus propias ventajas inconfundibles. No Agrupados. En nuestro ejemplo. Las consultas que filtran registros por medio de estos campos. Los Desencadenadores Un desencadenador es un objeto que existe sólo dentro del marco de una tabla. Página 4 .1. Los índices generalmente no se consideran parte de la base de datos. la información se guarda en el orden de los números de página. Sin embargo. donde existe algún tipo de valor (“clave”) de búsqueda que se organiza de una forma y. Un índice funciona de una forma análoga al índice de un libro.1. En cierto sentido.1. Tener un índice agrupado significa que la tabla que se basa en dicho índice agrupado está ordenada físicamente según dicho índice. Los índices pueden ser creados con cualquier combinación de campos de una tabla. En un libro.5. Los desencadenadores son elementos de código lógico que se ejecutan automáticamente cuando se producen diversos eventos en nuestra tabla. Las restricciones confinan los datos de nuestra tabla para satisfacer determinadas condiciones. Los desencadenadores se pueden utilizar para diversas cosas. pues son un detalle agregado. 4. 4. las restricciones compiten con los desencadenadores como posibles soluciones para solucionar problemas de integridad de datos. Un índice nos proporciona métodos para agilizar la búsqueda de nuestra información. no son iguales. Restricciones Una restricción es otro objeto que sólo existe dentro de los confines de una tabla.4. Programación en ADO. 4. Las Clave Índice Las claves índices surgen con la necesidad de tener un acceso más rápido a los datos. pueden encontrar los registros de forma no secuencial usando la clave índice. serían los conceptos detallados en el índice del libro. Se pueden tener tantos índices no agrupados como se quiera en la tabla. actualizaciones o eliminaciones.3. pero principalmente se utilizan para copiar datos a medida que se introducen o para comprobar la actualización para asegurarse de que se satisfacen algunos criterios. el índice agrupado sería el número de página.

se puede hacer una vista a la medida para que los usuarios no tengan que realizar búsquedas a través de información innecesaria. Programación en ADO. sería un método. los nombres de columna de cada tabla y las relaciones entre las mismas. Evidentemente es el objeto más importante. Básicamente se utilizan como una tabla. Podemos usar una vista para incluir la información que todo el mundo pueda ver. Capítulo 4. Diagramas Un diagrama es una representación visual del diseño de la base de datos. Vistas Una vista es algo parecido a una tabla virtual. En su lugar.7. una vista es simplemente una planificación previa de la asignación y representación de los datos guardados en tablas. 4. 4.1. dado que las aplicaciones normalmente discriminan la información en función del nivel de acceso del usuario.1. Procedimientos Almacenados Un procedimiento almacenado sigue siendo básico para las funciones de programación en SQL Server. Los datos recuperados pueden o no reunir unos criterios especiales (dependiendo de la definición de la vista) para mostrarse como datos en dicha vista. El plan se guarda en la base de datos en forma de consulta. Esta consulta llama a los datos de algunas columnas (no tienen que ser todas) para su recuperación por parte de una o más tablas. incluyendo las diversas tablas. Asimismo. pero existen otros que lo complementan y añaden la funcionalidad necesaria para sacar toda la potencia a un sistema de base de datos relacional. Página 5 . 4. Un procedimiento almacenado es una serie de instrucciones Transact-SQL ordenadas e integradas en una sola unidad lógica. pero no contienen ningún dato propio.8.6. Su equivalente en C#. Un Diagrama de entidad-relación (ERD). es un diagrama en el que la base de datos se divide en dos partes: las entidades y las relaciones. La tabla es el elemento básico de la estructura en una base de datos.1.

Insertar registros en la tabla. Los comandos o instrucciones más habituales en SQL se aplican para: Crear y borrar tablas. actualizar la información de los registros en la tabla. 4. A partir de la versión 2005 fueron sustituidas por AdventureWorks. Microsoft mantiene tanto Pubs como Northwind disponibles para SQL Server 2005 y SQL Server 2008. Página 6 . Si no hemos manipulado el ejemplo. Update. Estas opciones son realizadas por: Create. Drop. forman la base de todos los comandos que vamos a ver. La instrucción SELECT La instrucción Select y las estructuras utilizadas en ella. El uso del * le indica al intérprete de SQL que nos devuelva todos los campos (columnas) que tiene la tabla employees. respectivamente. Esta última base incorpora funcionalidades de SQL Server 2005 muy avanzadas que en ocasiones dificultan el aprendizaje del T-SQL. Capítulo 4. le indica cual es la tabla o tablas de las que tiene que tomar los datos. 4. Como primera prueba de Select. fueron diseñadas para su uso con Access y SQl Server 2000.2. La clausula FROM. T-SQL es un lenguaje estándar para trabajar con bases de datos relacionales y es soportado por la mayoría de los sistemas actuales. Sintaxis: SELECT <lista de columnas> [ FROM <tabla o tablas de origen> ] [WHERE <condición restrictiva>] [GROUP BY <nombre de columna o expresión que utiliza una columna en la lista de selección>] [HAVING <condición restrictiva basada en los resultados de GROUP BY>] [ORDER BY <lista de columnas>] Para empezar vamos a utilizar el ejemplo Northwind suministrado como ejemplo de ayuda por Microsoft.2. Programación en ADO. Tanto esta base como Pubs. usemos la siguiente sintaxis: SELECT * FROM employees El resultado de esta consulta nos dará todas las columnas (*) de la tabla employee y todos los registros que contenga. Delete y Select.1. borrar un registro o grupo de registros y. Uso básico de Transact-SQL o T-SQL Las bases de datos relacionales usan un lenguaje de programación conocido como Transact-SQL o T-SQL. deberá de dar como resultado nueve filas. Insert. seleccionar un registro o conjunto de registros. Por ello.

Hasta ahora. firstname FROM employees WHERE Title = 'Sales Representative' Como observaremos. NOT se evalúa primero. firstname FROM employees Como podemos ver los campos que queremos obtener van separados por coma. Hemos utilizado la columna Title. AND. Podemos cambiar el orden de evaluación colocando paréntesis. Por ejemplo: SELECT y Select son la misma cosa para el intérprete de SQL. Página 7 . Se pueden utilizar para combinar múltiples condiciones. sólo hemos obtenido el total de las filas que contiene la tabla. para restringir las filas que queríamos consultar. Esta cláusula nos permite agregar a la consulta condiciones sobre los resultados deseados. ahora son sólo seis. Hay algunos editores de SQL que ponen las instrucciones en mayúsculas y otros en minúsculas. Si quisiéramos obtener sólo las columnas de nombre y apellidos. Si ejecutamos la consulta veremos que siguen saliendo 9 filas pero sólo nos da las columnas LastName y FirstName. OR. BETWEEN La comparación es verdadera si valor se encuentra comprendido entre los valores facilitados. ya no son 9 las filas afectadas. Por ejemplo. La cláusula Where. Programación en ADO. A continuación vemos una tabla con los operadores que podemos utilizar en una cláusula Where: Operador Uso < Menor que > Mayor que < > y ¡= Distinto de <= Menor ó Igual que >= Mayor ó Igual que = Igual que ¡> No mayor que <! No menor que AND. Una cosa a tener en cuenta con el SQL es que no distingue a la hora de escribir las sentencias entre mayúsculas y minúsculas. utilizaremos la sentencia SELECT con esta estructura: SELECT lastname. después y por último OR. supongamos que queremos los empleados SELECT lastname. NOT Valores lógicos booleanos estándar. LIKE Utiliza los caracteres % y _ como Capítulo 4. pero sólo tiene un efecto visual.

Programación en ADO. al menos. _ indica que cualquier carácter puede reemplazar a este carácter. >=). Eso podría ser por casualidad. [ ] los corchetes indican que cualquier carácter único dentro de dichos corchetes es correcto. cualquier carácter entre la a y la z es válido. ANY y SOME son equivalentes funcionales y se evaluarán como true si la expresión se corresponde con cualquier valor del conjunto. SOME Devuelve true si alguno o todos los valores (dependiendo del elegido) en una subconsulta coinciden con la condición del operador de comparación (por ejemplo. por ejemplo [a- z]. = . Devuelve true si la subconsulta devuelve. ALL. la consulta sería: SELECT * FROM employees WHERE hiredate BETWEEN '01-01-1990' AND '01-01-1993' El resultado de esta consulta es de tres filas afectadas. % indica que un valor de cualquier longitud puede reemplazar al %. IN Devuelve true si el valor que se encuentra a la izquierda de la palabra clave IN se corresponde con cualquier valor de la lista proporcionada tras la palabra clave IN. comodines. La cláusula Order By. una fila. EXISTS. >. puede ocurrir que los datos salgan ordenados alfabéticamente. Normalmente se utiliza en subconsultas. En las consultas. ^ este carácter funciona como operador NOT indicando que se excluye el siguiente carácter. ALL indica que el valor tiene corresponderse con todos los valores del conjunto. En este caso. Página 8 . Capítulo 4. ANY. <. Si no le indicamos que deseamos ordenar los resultados de la consulta de una forma específica. Por ejemplo. si quisiéramos obtener todos los trabajadores cuya alta en la empresa sea entre 1990 y 1993. se obtendrán los datos en la forma menos costosa para recopilar los datos.

SELECT * FROM employees WHERE hiredate BETWEEN '01-01-1990' AND '01-01-1993' ORDER BY hiredate. colocando ASC. La cláusula Group By. Por ejemplo: SELECT * FROM employees ORDER BY FirstName. utilice la columna employeeid para ordenar. LastName En este ejemplo seleccionamos todos los empleados. no es necesario colocar una cláusula Where. muestra todos los valores cuyo campo unitsonorder sea superior a cero y su campo unitsinstock se inferior a 10. observaremos que en esta ocasión los datos son mostrados en el orden alfabético de la columna FirstName. DESC le indica que la ordenación sea descendente.Normalmente se basará. employeeid DESC Nos muestra la consulta ordenada primeramente por la columna. hiredate. Página 9 . Podríamos indicárselo de forma explícita. incluso cambiar si es ascendente o descendente. de forma descendente y si hubiera coincidencias. tiene que ir antes del Order By. Esta cláusula se utiliza para agregar información. pero mostrados en orden alfabético por el FirstName y después por el LastName. bien en el orden físico de una tabla o bien en uno de los índices de SQL Server utilizados para buscar los datos. pero en caso de ir. Evidentemente podemos aplicar ordenaciones por campos numéricos. El resultado es ordenador de forma descendente por unitsonorder. Si no queremos. nos devolverá todos los artículos que se han pedido dentro de un conjunto concreto de pedidos. Order By nos permite seleccionar cual es la columna o columnas que serán la base para ordenar los resultados de la consulta. Programación en ADO. Si realizamos la siguiente consulta. Ejemplo: SELECT * FROM employees WHERE hiredate BETWEEN '01-01-1990' AND '01-01-1993' ORDER BY FirstName Si observamos esta consulta respecto a la anterior. De forma implícita un Order By ejecuta la ordenación de forma ascendente. Capítulo 4. por ejemplo: SELECT * FROM products WHERE unitsonorder > 0 AND unitsinstock < 10 ORDER BY unitsonorder DESC Este ejemplo.

Si ejecutamos la orden como sigue. pero sólo vamos a estudiar las más usuales: sum. la consulta nos ha devuelto el detalle individual de cada pedido. toda columna en la lista de selección tienen que formar parte de Group By o tiene que ser un agregado. que en este caso. Programación en ADO. SELECT orderid. avg (media). Si quisiéramos ver sólo los pedidos. Un agregado es una función que actúa sobre grupos de datos. Realiza una media de los valores. Agregados. podemos utilizar la función Count(). employeeid. AVG. aplicarle un agregado a la sentencia select. COUNT(*) FROM orders WHERE customerid BETWEEN 'A' AND 'B' GROUP BY customerid.SELECT orderid. employeeid Esta consulta obtiene todos los pedidos por clientes y por empleados que hicieron esos pedidos. pero si lo que necesitamos es el número de filas. lo que significa que aunque en realidad la orden era sólo para ver tres pedidos. podemos ver que por ejemplo de la orden 11000 hay tres filas. min. Al usar Group By. además. sin él detalle. Cuatro filas para el pedido 11001 y 4 filas para el pedido 11002. Hay muchas clases de agregados. Capítulo 4. count. sólo OrderId). podemos usar Group By y. Página 10 . quantity FROM [order details] WHERE orderid BETWEEN 11000 AND 11002 Como podemos observar al ejecutar la consulta. El resultado es que para cada cliente nos dice el número de pedidos que gestiono los empleados. En el ejemplo que usamos el agregado SUM(). es la función de la suma sum(). Por ejemplo: SELECT orderid. Ejemplo: SELECT customerid. obtendremos tres filas con el total del valor del pedido. lo que obtuvimos fue la suma de la columna quantity. max. La suma se calcula y se devuelve sobre la columna seleccionada para cada grupo definido en la cláusula GROUP BY(en ese caso. SUM(quantity) FROM [order details] WHERE orderid BETWEEN 11000 AND 11002 GROUP BY orderid Sum() realiza la suma. AVG(quantity) FROM [order details] WHERE orderid BETWEEN 11000 AND 11002 GROUP BY orderid Esta instrucción ha calculado el importe medio para cada pedido. Si observamos detenidamente. que son las que coinciden con el orderid entre el 11000 y el 11002. nos ha devuelto 11 filas de la tabla order details.

Programación en ADO. utilizaremos una sentencia como esta: SELECT COUNT(fax) FROM customers En este caso hemos pedido saber cuántas filas hay en la tabla customers. Si observamos la ventana de mensajes cuando ha realizado la primera consulta. MAX(quantity) FROM [order details] WHERE orderid BETWEEN 11000 AND 11002 GROUP BY orderid COUNT(expression). hacen un total de 91. si quisiéramos saber cuántas son null. Si por el contrario ejecutamos esta orden: SELECT COUNT(*) FROM employees El resultado será nueve. Por ejemplo. El resultado es 69. La respuesta está en los valores null. En este caso sólo hay una fila.” Significa que cualquier valor null sobre un agregado del tipo. Devuelve el valor mínimo o máximo de una agrupación. utilizaremos la siguiente sentencia: SELECT COUNT(*) FROM customers WHERE fax IS NULL El resultado de la consulta es 22. descubriremos que el resultado es 91. sino que se aplica sobre todas las filas que no contienen null. ¿Cómo puede ser?. no son consideradas para el cálculo y por tanto no cuentan. las columnas que contienen el null. Capítulo 4. Por ejemplo: SELECT COUNT(*) FROM employees WHERE employeeid = 2 Devuelve el número de filas que el campo employeedid es igual a 2. MIN / MAX. En ese caso. el valor no está representado sobre todas las filas. vernos un mensaje con este texto: “Advertencia: valor NULL eliminado por el agregado u otra operación SET. En una media. Nos ha dado el número total de filas que contiene la tabla employees. por el campo fax. count. Supongamos que queremos obtener el recuento para una columna concreta. Pero esta consulta podría hacernos pensar que el resultado es idéntico a preguntar por todos. Por ejemplo: SELECT orderid. etc. Página 11 . avg. que sumadas a las 69 que dio. Hace un recuento de las filas en una consulta. por ejemplo: SELECT COUNT(*) FROM customers Si ejecutamos esta consulta.

SELECT orderid. por ejemplo. Como count es un agregado. no podemos devolver filas basándonos en la agregación. Para resolver este problema tenemos la cláusula Having: SELECT reportsto AS manager. la cláusula Having se aplica al valor agregado de dicho grupo. en la cláusula group by no tiene que ir. COUNT(*) AS reports FROM employees GROUP BY reportsto En este ejemplo. Count se puede usar junto con Group By para. La cláusula HAVING. por tanto. saber que empleados reportan a que director: SELECT reportsto. como reports. SUM(quantity) AS Total FROM [order details] GROUP BY orderid HAVING SUM(quantity) > 300 En este caso solo nos da dos filas afectadas. COUNT(*) FROM employees GROUP BY reportsto Hemos agrupado los resultados por reportsto. Por ejemplo: SELECT reportsto AS manager. podríamos usar una cláusula Having como sigue a continuación: SELECT orderid. Página 12 . podemos realizar esta otra consulta que nos devolverá 830 filas. SUM(quantity) AS Total FROM [order details] GROUP BY orderid Si quisiéramos filtrar la instrucción para que sólo nos de aquellos cuya cantidad es superior a 300. Mientras que la cláusula Where se aplica a todas las filas antes de convertirse en grupo. COUNT(*) AS reports FROM employees GROUP BY reportsto HAVING COUNT(*) > 4 Por ejemplo. La cláusula Having se usa si existe una cláusula GROUP BY en la consulta. Capítulo 4. Si usamos la cláusula Where no podemos hacer nada porque Where se ejecuta antes de la agregación y. El resultado puede ser equivoco. ya que presupone que todo el mundo de la empresa depende de dos directores. la columna reportsto aparece con el nombre de manager y la columna del count. Programación en ADO. Y si queremos que sólo aparezcan los directores que tienen a su cargo más de cuatro personas.

Predicados Distinct y ALL Supongamos que deseamos obtener un listado de todos los Id de proveedores de todos los productos que tenemos almacenados. pasaría por el uso del predicado Distinct. siempre que este permitido. La instrucción INSERT Insert es una instrucción de acción. Para el siguiente ejemplo usamos Pubs. si sólo queremos saber que proveedores tienen productos. La sentencia podría ser: SELECT supplierid FROM products WHERE unitsinstock > 0 La sentencia nos devuelve toda la lista de productos. Ejemplo de Insert: INSERT INTO stores VALUES ('Prue'. lo que significa que incluye todas las filas.2. 4. podemos usar Null. 'Prueba 15'. „Madrid‟. Es opcional. Le indica a SQL Server lo que vamos a hacer con esta instrucción. van los valores de las columnas separados por comas y entre paréntesis. 'Prueba Almacen'. pero si no suministramos ninguna. tenemos que tener mucho cuidado de asegurarnos que los valores corresponden a las columnas. Página 13 . ya que todo lo que va a continuación son los detalles de la operación. A continuación y después de la palabra VALUES. Si queremos no establecer un valor en una columna podemos usar la palabra default para que la base de datos ponga uno predeterminado. Es completamente opcional pero su uso es recomendable por el tema de la legibilidad. Por defecto siempre el predicado es ALL. La sentencia podría quedarnos: SELECT DISTINCT supplierid FROM products WHERE unitsinstock > 0 Ahora sólo muestra un Id de proveedor aunque aparezca en más de una fila. '00319') Capítulo 4. También y. Su único propósito es que la instrucción sea más legible. repitiendo el id de proveedor cada vez que hay un producto de ese proveedor. La solución. Sintaxis: INSERT [intro] <tabla> [(lista_de_columnas)] VALUES (valores_de_datos) La palabra clave intro es de relleno.2. 'MD'. Después de intro viene la tabla en la que deseamos insertar los valores: La lista de columnas. Podemos prescindir de una lista explícita (son listas donde se especifica concretamente que columnas recibirán los valores). Programación en ADO.

Veamos un ejemplo en que facilitamos una lista de columnas: INSERT INTO stores (stor_id. Nota: Existe un procedimiento almacenado en el sistema que permite ver las propiedades de cualquier objeto de la base de datos en la ventana de consultas: sp_help. El valor más común de este tipo es un valor Identity. lo ideal hubiera sido haber suministrado una lista de columnas explícita. nos dará el siguiente error: “Infracción de la restricción PRIMARY KEY 'UPK_storeid'. stor_name.stores'. Un valor predeterminado es un valor constante que se inserta si no se proporciona ningún valor. 'MD'. '00319') En este segundo ejemplo hemos omitido el campo correspondiente a stor_address. Suministramos un valor para la columna. Si intentamos repetir la instrucción. Si comprobamos la inserción descubriremos que en la columna que no hemos dado un valor a colocado null. zip) VALUES ('Pru2'. dará de alta la fila colocando un null en esa columna. La ejecución de esa instrucción genera una nueva fila dentro de la tabla stores. entonces debemos de usar la instrucción Select en la sintaxis de la instrucción Insert. Página 14 . Si una columna no permite null. pero no importa porque al ser un campo que permite valores null. No se puede insertar una clave duplicada en el objeto 'dbo. Capítulo 4. city. El hecho de usar una lista de columnas nos permite especificar qué valores van a qué columnas. Si necesitamos insertar más de una fila. Para poder ejecutarlo usaremos la siguiente sintaxis: EXEC sp_help sales Instrucción Insert Into .” El motivo es porque la columna stor_id es un campo de Clave Primaria y no admite repeticiones.Select La instrucción Insert que hemos desarrollado permite insertar sólo una fila cada vez. Una columna que acepta valores null permite que en una instrucción Insert se omitan valores para esa columna. 'Prueba Almacen'. A pesar de que ha funcionado bien. state. Programación en ADO. entonces hay que proporcionar una de estas tres condiciones: La columna se ha definido con un valor predeterminado. La columna está definida para admitir valores generados por el sistema. 'Madrid'.

Sintaxis: INSERT INTO <nombre_tabla> [<lista_columnas>] <instrucción SELECT> En una instrucción Insert con Select podemos seleccionar los registros a insertar de distintos orígenes: Otra tabla de nuestra base de datos. pero sólo una tabla a la vez puede estar sujeta a la acción de la actualización. Programación en ADO. Una instrucción Update puede crearse a partir de varias tablas pero sólo puede realizar cambios a una. De la misma tabla (normalmente para ordenar cálculos matemáticos). Sintaxis: UPDATE <nombre de tabla> SET <columna> = <valor> [.dbo. Página 15 . o recuperar valores de cualquier número de tablas distintas.Orders WHERE OrderId BETWEEN 10240 AND 10250 SELECT * FROM @mitabla Ejemplo: Uso InsertarTablaMemoria 4. <columna> = <valor> ] [FROM <tabla-s de origen>] [WHERE <condición restrictiva>] Capítulo 4.2. Una consulta de otro SQL Server u otros datos. CustomerId char(5) ) INSERT INTO @mitabla SELECT OrderId. En el siguiente ejemplo creamos una tabla en memoria y le asignamos por mediación de la sentencia Insert con Select datos de la base de datos Northwind. Esto quiere decir que podemos crear una condición. La instrucción UPDATE La instrucción Update permite modificar valores de registros que se encuentran en la tabla.3. Una base de datos totalmente diferente en el mismo servidor. tabla orders: USE northwind DECLARE @mitabla Table ( OrderId int. CustomerId FROM northwind.

4. Capítulo 4. Si quisiéramos ajustarlo podemos utilizar una función de redondeo. Ahora. La instrucción DELETE La instrucción Delete puede que sea de las que hemos visto hasta ahora de las más sencillas.2. Programación en ADO. sin tener en consideración más valores dentro de la cadena. viendo el resultado. supongamos que queremos actualizar el valor de la columna city. observaremos que cada elemento tiene un número variable de decimales. UPDATE titles SET price = ROUND(price * 1. Si volvemos a realizar un Select para ver los resultados. para todos aquellos libros cuyo campo title_id empiecen por „BU‟. Sintaxis: DELETE <nombre_tabla> [WHERE <condición_busqueda>] La cláusula Where funciona como hemos venido viendo hasta ahora. vamos a aplicar una sentencia Update usando el operador Like para cambiar el precio en los libros que coincidan en la consulta: UPDATE titles SET price = price * 1. price FROM titles WHERE title_id LIKE 'BU%' Al ejecutarla vemos que muestra todos los títulos que empiezan por „BU‟. Tomando la base de datos Pubs.1 WHERE title_id LIKE 'BU%' Este ejemplo actualiza los valores de la columna precio. state = 'CM' WHERE stor_id = 'prue' Pero los cambios pueden afectar a grupos de registros que cumplan una condición. Por ejemplo vamos a probar una sentencia Select en la que aplicamos el operador Like: SELECT title_id. pero podemos cambiar varias columnas a la vez: UPDATE stores SET city = 'Toledo'.1. de la tabla stores: UPDATE stores SET city = 'Toledo' WHERE stor_id = 'prue' En esta sentencia hemos cambiado el valor de una sola columna. ya que la posibilidad de borrar es a toda la fila y no a una parte de ella. incrementando su valor en un 10%. 2) WHERE title_id LIKE 'BU%' 4. No incorpora listas de campos. Página 16 .

es necesario borrar antes los que dependen de él. Esto hace que al final los datos se tengan que tomar de más de una tabla. mejorar el rendimiento y aumentar la integridad de datos. Para poder borrar el registro. Se perdería la integridad referencial. A JOIN hay que indicarle como queremos que se una la información. El conflicto ha aparecido en la base de datos "pubs". que incluye: INNER JOIN OUTER JOIN (tanto LEFT como RIGHT) FULL JOIN CROSS JOIN Usamos JOIN para combinar la información de dos o más tablas en un solo conjunto de resultados. En el siguiente esquema podemos ver un ejemplo del uso de JOIN Capítulo 4.2. tabla "dbo. Página 17 . tiene su campo clave y está relacionado con la tabla sales. Programación en ADO. El conjunto de resultados puede ser tratado como una tabla virtual. column 'stor_id'. La cláusula JOIN En las bases de datos relacionales las tablas grandes se suelen dividir en tablas más pequeñas para evitar la redundancia de datos. No nos deja borrar la fila porque si lo hace dejaría huérfanos registros en otras tablas. columna stor_id. tipos de datos y valores. El proceso de combinación de tablas en un conjunto de resultados requiere el uso de la cláusula JOIN. 4. Este error se produce porque la tabla stores.sales". Cuando una base de datos está normalizada es cuando se han aplicado técnicas de diseño que permiten tener las tablas grandes en tablas más pequeñas. Ejemplo: DELETE stores WHERE stor_id = 'prue' Puede ocurrir que en una operación Delete aparezca un mensaje como el que aparece a continuación: Instrucción DELETE en conflicto con la restricción REFERENCE "FK__sales__stor_id__0AD2A005". ahorrar espacio.5. Tiene columnas.

obtenemos una tabla de resultados. Programación en ADO. 4 Ibiza 2 Tabla Fabricantes IDFabricante Nombre Fabricante 1 Citroen 2 Seat 3 Renault Tabla Resultado de aplicar una sentencia JOIN IDFabricante Nombre Fabricante IDCoche Modelo Coche 1 Citroen 1 Xara Picaso 1 Citroen 3 C5 Como podemos ver la tabla Fabricantes tiene un campo clave llamado IdFabricante que vincula esta tabla con la tabla Modelos. Al usar una sentencia JOIN en una consulta con ambas tablas. IDFabricante en la tabla modelos. con el registro seleccionado de la tabla fabricante. Tabla Modelos IDCoche Modelo Coche IDFabricante 1 Xara Picaso 1 2 Megant 3 3 C5 1 Campo Clave El campo IDFabricante Relaciona ambas tablas. cuyo IDFabricante sea el mismo. En el ejemplo obtenemos los modelos para Citroen. en la que se unen los registros que coinciden con el campo. Sintaxis: SELECT <lista de selección> FROM <primera tabla> <tipo_de-unión> <segunda tabla> [ON <condición_de_unión>] Capítulo 4. Página 18 .

pero INNER JOIN devuelve sólo los registros que se corresponden con el campo (o campos) que hayamos especificado en JOIN. En el siguiente ejemplo usamos la base de datos Northwind: SELECT * FROM Products INNER JOIN Suppliers ON Products. Para crear un alias. companyname FROM Products tp INNER JOIN Suppliers ON tp. pero no se sabe qué columna proviene de que tabla. Un JOIN del tipo INNER JOIN es una unión exclusiva. como la mayoría de cláusulas JOIN. debido a los problemas de lectura que acarrea.SupplierID Si nos fijamos en el resultado de la consulta.companyname FROM Products tp INNER JOIN Suppliers ts ON tp. Además.SupplierID = Suppliers.SupplierID En este ejemplo. ts. Empareja los registros basándose en uno o más campos comunes. hay que usar el alias en todas las apariciones del nombre de la tabla en la consulta. Aparecen todas las columnas porque en el Select le hemos indicado con el * que ponga todas. es decir. INNER JOIN Esta cláusula es la más conocida de JOIN.supplierid.SupplierID = ts.*. Supongamos otro ejemplo: SELECT tp. Página 19 . tp. Vamos a ver otro ejemplo. justo detrás del nombre de la tabla va el alias: SELECT tp. Programación en ADO. En el select hemos especificado que columnas y en qué orden queremos que aparezcan en la tabla de respuesta. Esto no es muy recomendable en una sentencia Join.SupplierID = Suppliers. Imaginemos que nos piden cuales son los clientes que nos han hecho algún pedido. Para ello necesitamos la tabla Capítulo 4. de todos nuestros productos.productid. Supongamos que lo que queríamos era el nombre del proveedor. ts. por último. podemos observar que se han devuelto todas las columnas de ambas tablas y. excluye todos los registros que no tienen un valor en ambas tablas.productname. usamos el alías tp para la tabla productos y el alias ts para la tabla suppliers. descubriremos que la columna SupplierID (ID Proveedor) aparece dos veces. entonces la consulta podría quedarnos así: Vamos a realizar la misma consulta pero esta vez usando un alias para el nombre de la tabla. las primeras columnas son de la primera tabla.SupplierID Si usamos un alias.

los títulos. el operador + concatena los string en uno sólo.au_id INNER JOIN titles tl ON tl.au_lname + '. Normalmente existen otros métodos para conseguir lo mismo. tl. JOIN tiene lados (uno izquierdo y otro derecho).title_id El operador + utilizado en el Select. Página 20 . Por tanto. OUTER JOIN Este tipo de cláusula es más bien una excepción. El campo CustomerID de la tabla Customers. no una regla y no porque no tenga su uso.customerid = tod. es la relación existente entre ambas tablas. Esta concatenación deja en una columna a la que llamamos Autor. utilizando tres tablas. el contenido de los dos campos separados por una coma. pudiéndose colocar cualquier símbolo o carácter. Como en cualquier lenguaje que maneje string.title_id = tt.Customers(Clientes) y Orders(Pedidos). tc. A veces es un desconocimiento por parte de los programadores.customerid. Para que un pedido sea válido necesitamos dar de alta el ID del cliente en el pedido. Lo primeo que podemos observar es que en la tabla authors. Buscamos una consulta que devuelva todos los autores que han escrito libros y los títulos de dichos libros. La primera tabla con nombre se considera que está a la izquierda y la segunda que está a la Capítulo 4. Programación en ADO. La coma que aparece entre los dos es por un tema visual.title FROM authors ta INNER JOIN titleauthor tt ON ta.au_id = tt.companyname FROM Customers tc INNER JOIN Orders tod ON tc. ' + ta. pero hay una tabla llamada titleauthor. no todos los pedidos.au_fname AS "Autor". Pueden resultar muy útiles desde el punto de vista del rendimiento cuando se utilizan en lugar de subconsultas anidadas. También se las conoce como tablas unión o asociadas. la sentencia podría ser: SELECT DISTINCT tc. tenemos el autor y en la tabla titles. permite ver el contenido del campo Lname y Fname en uno solo. En principio no tenemos nada que los una. sino por lo siguiente: Normalmente deseamos la exclusividad proporcionada por INNER-JOIN.customerid Hemos usado la palabra clave DISTINCT porque sólo queremos conocer que clientes han hecho algún pedido. Una cláusula INNER JOIN es exclusiva. SELECT ta. mientras que OUTER JOIN y FULL JOIN son inclusivas. Probemos un ejemplo que combina dos JOIN sobre la base de datos Pubs. que es una tabla que resuelve las relaciones de varios a varios.

le estamos diciendo que tome toda la información de la tabla que está a la derecha. Capítulo 4.stor_id = ts. Siguiendo con el ejemplo anterior.stor_id Podemos comprobar que nos ha devuelto todas las filas de discounts. Esto es muy importante cuando especificamos con Left o Right. los que existen actualmente. la consulta resultaría: SELECT discounttype. con RIGHT OUTER JOIN. ¿Qué ocurre si cambiamos el LEFT por RIGHT: SELECT discounttype.stor_id = ts. Página 21 . Supongamos que necesitamos saber cuáles son nuestros descuentos.stor_name FROM discounts td JOIN stores ts ON td.stor_id = ts. Programación en ADO. Cuando se ejecuta. El tema es que la tabla que aparece antes del OUTER JOIN es la izquierda y la que aparece a continuación es la derecha. la cantidad total de cada uno y las tiendas que los utilizan. dos son null y el tercero es el nombre de una tienda. podremos ver que tenemos la siguiente tabla sobre descuentos (discounts) y tiendas (stores).derecha. En las cláusulas OUTER JOIN. muestra un null. veamos como lo podemos aplicar para buscar tiendas que no tengan asignados ningún tipo de descuento.stor_id Aunque parece un cambio pequeño cambia totalmente la salida de la consulta. INNER JOIN trata a los dos lados de la misma forma. En nuestro caso de los tres registros que salen. en la tabla de la derecha si una fila de la tabla discounts no tiene una coincidencia con la tabla stores. stor_id. Si lo hiciésemos con INNER JOIN. Buscamos los descuentos que tenemos. ts. Buscamos todos los descuentos y las tiendas donde se aplican: SELECT discounttype. discount. Podemos unir estas dos tablas basándonos en el ID de tienda. es muy importante saber cuál es nuestro izquierdo y derecho. Si decimos LEFT OUTER JOIN le estamos diciendo agrega toda la información de la tabla que está a la izquierda y.stor_id El resultado sería de sólo una fila. discount. ts. Pero esta consulta sólo nos proporciona los descuentos para los que existen tiendas correspondientes. Una de las ventajas que nos puede ofrecer OUTER JOIN es la posibilidad de encontrar registros huérfanos o no coincidentes.stor_name FROM discounts td RIGHT OUTER JOIN stores ts ON td. discount.stor_name FROM discounts td LEFT OUTER JOIN stores ts ON td. ts. Si examinamos nuestra base de datos pubs.

si no existe ningún registro en discounts.stor_id también tiene un valor NULL.stor_name AS 'Nombre de la Tienda' FROM discounts td RIGHT OUTER JOIN stores ts ON td. Un valor NULL nunca es igual a otro valor NULL. teniendo desactivados los ANSI_NULLS a través de las opciones de servidor o de una instrucción SET. si existen registros en discounts. Si stores. Usamos la base de datos Pubs. según el operador ON de la cláusula JOIN.stor_id se devolverá como NULL. un valor null nunca es igual a otro valor null.5.stor_id devolverá NULL porque no existe ningún valor coincidente.0. Con FULL JOIN podremos obtener todos los registros coincidentes basándonos en el campo (o campos) de JOIN. Aunque al principio parece una muy buena elección. entonces. según el operador ON de la cláusula JOIN.stor_id (ON td. Una cláusula OUTER JOIN nos devuelve un valor null en las columnas basadas en los descuentos siempre que no exista una correspondencia. luego casi nunca se usa. El tener desactivado los ANSI_NULLS es una infracción al estándar ANSI y ya no es compatible con la configuración actual de SQL Server. Ejemplo: Capítulo 4. hace corresponder los datos de ambos lados de JOIN. FULL JOIN Esta cláusula también es conocida como FULL OUTER JOIN. Programación en ADO.stor_id) Si la columna stores. devolviéndose todas las columnas con valores NULL de la parte derecha. independientemente del lado JOIN que sea. También podremos obtener cualquier registro existente en la parte de la izquierda.stor_id tiene un valor NULL y discounts.stor_id = s. entonces discounts.stor_id IS NULL El resultado de esta consulta son cinco filas afectadas donde la tienda no tiene asignado ningún tipo de descuento.stor_id tiene un valor distinto de NULL. entonces. Si analizamos la consulta comprobamos lo siguiente: Si la columna stores.stor_id WHERE td. Nota: A partir de la versión SQL server 7. entonces discounts. Ejemplo: SELECT ts.stor_id = ts. devolviendo los valores NULL de las columnas de la parte izquierda. Pero puede ocurrir que mantenga el servidor de SQL compatibilidad con la versión 6.stor_id tiene un valor distinto de NULL. Página 22 . no existiría ninguna unión y discounts. Pero también podemos obtener cualquier registro existente sólo en la parte derecha.stor_id también tiene que tener el mismo valor que stores.

a diferencia de las otras instrucciones JOIN. Crear la Base de Datos: CREATE DATABASE <nombrebasedatos> Crear la tabla: CREATE TABLE [nombrebasedatos] nombretabla(<nombrecolumna> <tipodatos>) Estructura de los tipos de datos: Tipo SQL de . CROSS JOIN Es una cláusula bastante extraña en su funcionamiento y su uso bastante restringido. Página 23 .2.pub_name FROM authors ta FULL OUTER JOIN publishers tp ON ta.au_fname. ya que lo que hace en realidad es generar tablas cartesianas.city = tp.SELECT ta. Vemos un ejemplo de su aplicación: SELECT a.city ORDER BY tp.NET Tipo SQL Tipo MS Access Framework Integer Número entero largo SqlInt32 Real Número simple SqlSingle Float Número doble SqlDouble Char Texto SqlString Varchar Texto SqlString Binary Binario SqlBinary DATE Fecha/Hora SqlDateTime Capítulo 4. se suele aplicar. multiplicando el número de registros de una tabla por otra. y todas las filas de publishers a las que le añade el equivalente de authors.au_fname. colocando NULL cuando en la otra tabla no había valores.pub_name En este ejemplo podemos ver que ha obtenido los registros coincidentes de ambos lados. El comando Create soporta dos variantes en función de si creamos una Base de Datos. tp.au_lname. 4.pub_name FROM authors a CROSS JOIN publishers p Como podemos ver en los resultados. Programación en ADO. ta. o creamos una tabla dentro de la Base de Datos. obtiene todas las filas de authors. p. Es decir. a las que le añade el equivalente de publishers. Se sabe que para aplicaciones matemáticas.au_lname. No dispone del operador ON. Create Create se aplica tanto a bases de datos como a tablas.6. sabremos cuantos registros obtendrá la consulta. a.

el que verifique si existe el dato en la tabla y no sea necesario realizar por programa una comprobación. La diferencia entre ambos radica en que cualquier tipo de datos de SQl que empiece por N. Ejemplo de creación de una tabla: CREATE TABLE Empleados(Nombre VARCHAR(30) NOT NULL. Este campo será el punto de acceso de la base de datos a los datos de la tabla. La diferencia entre el tipo char y Varchar. Además de Varchar. utiliza la codificación Unicode que implica que para guardar un carácter utiliza dos bytes y por tanto. usa un juego de caracteres mucho mayor. Cuando se crean columnas en la base de datos. Departamento VARCHAR(30) NOT NULL) 4. radica en que el primero (longitud fija) rellena con espacios en blanco la longitud de texto que no se haya usado y el segundo no (longitud variable). Apellidos VARCHAR(50) NOT NULL. Para ello. sin ser Primary Key. La cláusula NOT NULL permite que no se pueda dejar un campo sin información. Esto hace que sea el propio sistema de bases de datos. ni valores duplicados (unique). mientras que Varchar. Programación en ADO. contenga datos que no sean duplicados. Esto significa que una columna del tipo Primary Key. Su sintaxis es la siguiente: Borrar la Base de Datos: DROP DATABASE <nombre de la base de datos> Crear la tabla: DROP TABLE <nombre de la tabla> Capítulo 4.2. podrá almacenar cualquier valor de bytes que no exceda su longitud máxima. es posible especificar si una columna concreta es la clave principal de la tabla (PRIMARY KEY). es decir. También podemos hacer que un campo. La instrucción DROP Esta instrucción permite borrar una base de datos o una tabla. existe en SQL el tipo NVarchar. Es decir. no puede tener ni valores del tipo null. por que se usa en idiomas como el japonés. Estos últimos no se suelen usar a no ser que se use por problemas de compatibilidad con aplicaciones o. Página 24 . que el campo contenga el valor de tipo null (sin datos). usaremos la cláusula UNIQUE. Direccion VARCHAR(100) NOT NULL.7. al final el char debe obligatoriamente grabar un número concreto de bytes definidos por su tamaño.

Para crear una tabla. dado que el objeto DataTable fuera de él no tenía muy buena funcionalidad. Una columna tiene dos valores importantes a definir: el nombre de la columna y el tipo de dato que contiene. Son tan importantes para el conjunto de datos. El DataSet ha sido siempre el núcleo de ADO . incluidos claves.3. El objeto DataColumn y DataRow 4. A partir de la versión de Net Framework 2. Un DataTable es en realidad un representación de una tabla de datos. y el objeto DataRow. Programación en ADO. especificando el nombre de la columna y el tipo de datos que guarda: Capítulo 4.4. 4. que han ido aumentando en prestaciones e importancia con las distintas versiones. se mejoró notablemente la clase DataTable. restricciones e incluso capacidad de consulta.0.3. Muchas veces se trabaja con una sola tabla. ADO. El DataTable. por mediación del DataTable y el DataSet. que permite acceder a las filas de la tabla. incluye la colección DataRowCollection de objetos DataRow (filas de la tabla). Podemos declarar la columna de dos formas: Podemos añadir columnas a la colección de columnas del objeto DataTable. donde encontramos otros dos objetos: el DataColumn.1. así como relaciones entre tablas usando el objeto DataRelations. El objeto DataTable El objeto DataTable.1. que permite especificar y manejar las columnas.1. es necesario empezar por definir las columnas que contendrán la tabla.3.Net. proporcionando una representación en memoria interna de datos relacionales. Además podemos aplicar restricciones usando el objeto Constrains. proveen de todos los elementos necesarios para desarrollar una base de datos sin necesidad de contar con un proveedor específico. convirtiéndola en un elemento muy importante y con una funcionalidad propia que hace que ya no sea dependiente del objeto DataSet. Página 25 . y el uso del DataSet era casi obligado. existen desde las primeras versiones de Net Framework. la colección DataColumnCollectiom de objetos DataColumn (columna de datos) y la colección ConstraintCollection de objetos Constraint (restricciones). El objeto DataColumn. Cargar valores en una tabla. al igual que el objeto DataSet que veremos más adelante.

Cadena). Apellidos y DNI. ColumnaIdentidad. campos clave y demás. 4. En este ejemplo.NewRow(). Página 26 .3. hemos creado una fila con la estructura que tiene el objeto DataTable. Programación en ADO.AutoIncrementStep = 1.DataType = typeof(int). La propiedad Unique a true indica que la columna es de valores únicos. como son los valores autoincrementados. lo razonable sería crear una fila nueva a partir del objeto DataTable: DataRow FilaInsertar = TablaDatos.AutoIncrementSeed = 1. Pero ahora es el momento de empezar a dar valores utilizando para ello el objeto DataRow. En este ejemplo.Add("Producto". la forma de dar valores sería: Capítulo 4. cuyo valor inicial es 1 (AutoIncrementSeed) y los incrementos serán de uno en uno (AutoIncrementStep). pero dado que usaremos el objeto DataRow para dar de alta una fila sobre un objeto DataTable ya creado. especificando manualmente las columnas que contendrá. Cuando cargamos las distintas columnas en el objeto DataTable. para posteriormente. Una variante de esta forma podría ser esta: Type Cadena = typeof(string). es la estructura de la tabla.Add(ColumnaIdentidad).2.AutoIncrement = true. la forma de agregarla a la colección de columnas del objeto DataTable sería: TablaDatos. typeof(string)). dar de alta los valores que contendrá la tabla. Este objeto tiene la finalidad de crear una fila que cumpla con la estructura de la tabla. ColumnaIdentidad.Columns. Pero si lo que queremos es utilizar más funcionalidades de las columnas. lo que significa que no puede contener valores repetidos.Unique = true. ColumnaIdentidad. TablaDatos.Add("Producto". ColumnaIdentidad. El objeto DataRow. En ambos casos declaramos la columna con su nombre y su tipo. TablaDatos.Columns. Una vez declarada la columna. Suponiendo que la tabla sea una tabla que contenga las siguientes columnas: Nombre. la forma sería: DataColumn ColumnaIdentidad = new DataColumn().1.Columns. lo que tenemos. TablaDatos. hemos creado una columna que será una columna del tipo autoincrementado. Podemos crear una fila. ColumnaIdentidad.

2. 4. para añadir los valores al DataTable: TablaDatos. Existe además el DataView. Como podemos observar. pudiendo conocer cualquier de estos estados: Added (añadir). 4. Programación en ADO.Count. podemos implementar un DataReader. FilaInsertar[2] = “5746565-K”. } En este ejemplo. búsqueda. Página 27 .Rows. DataRow.Add(FilaInsertar). Se comporta como una matriz o colección y el índice comienza en cero. richTextBox1. i < TablaDatos. Recorrer los valores de un DataTable Las filas de un objeto DataTable son una colección y por tanto podemos recorrerla con un bucle for o con un bucle foreach: for (int i = 0. En este ejemplo. el valor de la columna 1 (Fila[1]). Capítulo 4. Por último.Rows[i]. FilaInsertar[1] = "Sánchez Sánchez". Por mediación del objeto DataTableReader.Rows) richTextBox1. Fila. incluye la propiedad RowState. filtrado. cómo podemos observar. Deleted (borrar). utilizamos el nombre del objeto DataRow facilitando entre corchetes el número de columna al que deseamos dar valores. Modified (modificar) y Unchanged (sin cambios). Recorrer los valores de un DataTable usando un DataReader. es más cómodo utilizar un bucle foreach que un bucle for. que permite saber si la fila cambió y cúal fue el motivo del cambio. edición y exploración. Si en lugar de usar un bucle for usamos un bucle foreach: foreach (DataRow Fila in TablaDatos. También es posible dar el nombre de la columna en lugar del índice. que representa una vista personalizada que puede enlazar datos de un DataTable para ordenación.3.3. FilaInsertar[0] = "Alvaro".3. i++) { DataRow Fila = TablaDatos. con un funcionamiento similar a un ADO Conectado (este punto se verá más adelante en este mismo capítulo).Rows.Text += Fila[1]. obtenemos del objeto DataRow.Text += Fila[1].

convirtiéndola en un elemento muy importante y con una funcionalidad propia que hace que sea muchas veces útil sin necesidad de contar con un objeto DataSet. similar al uso que tienen en el DataSet.4.3. está la posibilidad de leer y cargar un fichero XML en el objeto. while (Lector. A continuación. utilizamos el método WriteXML. Automáticamente.ReadXml("Clientes. en este caso: MisClientes.xml dentro del DataTable.ToString()). En este ejemplo.Read()) { MessageBox. Dentro de las nuevas funcionalidades que se dieron al objeto DataTable. Página 28 . Capítulo 4. } En este ejemplo hemos implementado un objeto DataTableReader que nos permite recorrer el DataTable como si fuera una consulta realizada en modo ADO Conectado. cuando creamos el DataTable. Implementa los métodos ReadXml y WriteXml. Las columnas del lector son de tipo object.xml"). objDataTable. El método ReadXml permite leer un fichero XML a un objeto DataTable: DataTable objDataTable = new DataTable("MisClientes").Show(Lector[2]. se generan las columnas y las filas dentro del mismo. bien sea por su índice o por su nombre. En .5. al igual que si fuera un objeto DataRow. le damos un nombre a la tabla. Programación en ADO.CreateDataReader(). Ver Uso DataTable-01 4.3. Para poder realizar una escritura del DataTable en el fichero XML. Grabar un DataTable en un fichero XML. Las filas del DataTable son volcadas a Lector y. Otra de las posibilidades es escribir el contenido de un DataTable dentro de un fichero XML. El XML se ha convertido en un estándar para el intercambio de información entre proveedores de datos. lo que nos permite un fácil intercambio de información con los actuales sistemas de bases de datos y aplicaciones. cargamos el fichero clientes. usando el método ReadXml.0. se mejoró notablemente la clase DataTable. podemos sacar el valor de la columna. Cargar un fichero XML en un DataTable. DataTableReader Lector = TablaDatos. 4.Net disponemos de la posibilidad de cargar un DataTable desde un fichero en XML. A partir de la versión de Net Framework 2.

Add(new object[] { 4. el hecho de inferir esquemas en tiempo de ejecución desde XML provoca una excepción que indica que no es compatible con la clase DataTable.Columns.Add("NombreCliente". typeof(string)). Para evitar esto. objDataTable. en el ejemplo Uso DataTableXML. XmlWriteMode. En este ejemplo.xml". "María José".Rows. "Ana".Rows.Add("ApellidosCliente". "López Sánchez" }). objDataTable. "Jesus". objDataTable.Rows.Add(new object[] { 3.Rows. objDataTable. A pesar de que en la documentación de MSDN indica que la inferencia de esquemas es posible en un DataTable desde datos XML. objDataTable. objDataTable. typeof(string)).Add("IDCliente". se usa la opción XmlWriteMode. "Moreno López" }). Ejemplo Uso DataTableXML Capítulo 4.WriteSchema).Add(new object[] { 1. objDataTable. "Pedro".Columns.WriteSchema para incluir el esquema en la parte superior del documento. Página 29 . typeof(int)).Columns. usamos el método WriteXml de los DataTable para grabar el fichero XML con los datos contenidos dentro del DataTable. objDataTable.WriteXml("clientes. Programación en ADO.Add(new object[] { 2. "Martínez" }). "Sánchez Alpino" }). objDataTable.DataTable objDataTable = new DataTable().

y cada DataTable contiene datos de un solo origen. Cargar objetos DataTable en el DataSet El elemento básico de información dentro de un DataSet es el DataTable. Por ejemplo: //Damos nombres a las tablas. incluye la colección DataTableCollection de objetos DataTable (que son las tablas de datos) y la colección DataRelationCollection de objetos DataRelation (relaciones entre las tablas). Este DataTable.1. también puede ser cargado dentro del DataSet. volverá a realizar la conexión con el origen de datos. Página 30 . Cuando deseamos modificar ese origen de datos desde nuestra aplicación. Podríamos acceder directamente al origen de datos por mediación de comandos de SQL o procedimientos almacenados.TableName = "Categorias". El DataSet. como hemos visto anteriormente.Add(objDataTable1).Tables. Previamente. Esto nos permite crear DataTables dentro del DataSet. Para cargar un DataTable dentro del DataSet disponemos de la colección Tables del DataSet. Cada DataSet puede contener varios objetos DataTable.Add(objDataTable2).4. 4. En este ejemplo. podemos crear un DataTable con datos locales sin necesidad de conectar a ningún origen de datos en SQL. como SQL Server o Access.4. no tiene sentido crear un DataSet si luego no vamos a cargar en su interior objetos DataTable. Por tanto. objDataTable2. objDataSet. que almacena los datos leídos del origen de datos en un conjunto de datos. para después vincularlos entre sí Capítulo 4.Tables. Igualmente y.4.TableName = "Empleados". evidentemente. suministrándole la nueva información desde el conjunto de datos que se encuentra en nuestra máquina. 4. usando la propiedad TableName. objDataTable1. El objeto DataSet El DataSet representa una cache de memoria con datos y es el eje de la arquitectura ADO. ambos del tipo DataTable.2. añadimos a la colección Tables del DataSet el objeto objDataTable1 y el objetoDataTable2.4. objDataSet. //Agregamos las tablas al DataSet. Para conectar datos a un DataSet podemos usar un objeto DataAdapter (se estudiará más adelante). Es decir. hemos asignado un nombre a cada Tabla. Relacionar objetos DataTable Una función muy importante de los DataSet es la de manejar los DataTable como si de una Base de Datos Relacional se tratara. el DataSet puede mantener múltiples datos que pertenecen a distintos orígenes de datos. Programación en ADO.NET.

Ejemplo: //Creamos una columna que será columna clave del DataTable. typeof(int)). objDataTable1. //Especificamos que columna o columnas son la clave del DataTable. IdEmpleado. Ver Uso DataSet-ADO. En la siguiente figura podemos ver el diseñador de DataSet con varias tablas y las relaciones entre ellas. Pero en el caso de que necesitemos desarrollar todo el trabajo desde el código.Columns. IdEmpleado. campo clave y demás características que usaríamos en una tabla dentro de un gestor de bases de datos relacional.y aumentar las prestaciones de los datos. Diseñador de DataSet Relaciones entre DataTables Nombre del DataTable Columnas del DataTable. IdEmpleado.AutoIncrement = true. DataColumn IdEmpleado = new DataColumn("IdEmpleado".AutoIncrementSeed = 1. //Creamos una matriz de columnas con la columna o columnas que serán //Columna clave en la tabla. Si usamos el diseñador de DataSet definiremos las relaciones con las herramientas visuales que para ello tiene definido el objeto. IdEmpleado. Programación en ADO. especificando incluso las características de unicidad. //Agregamos la columna a la colección de columnas del DataTable objDataTable1. Capítulo 4. Objeto Objetos DataTable DataColumn Figura: Imagen del Diseñador de DataSet. los pasos a seguir son: Definir las columnas que actuaran como campos clave dentro del DataTable.Unique = true.AutoIncrementStep = 1.Add(IdEmpleado). //Será una columna de autoincremento y valores únicos.PrimaryKey = Claves. DataColumn[] Claves = { IdEmpleado }. Página 31 .

ClavePrincipal. Página 32 . ClaveForanea). Las filas coincidentes son guardadas en la matriz del tipo DataRow Filas.Add(relacionClaves). También podemos acceder por el índice del DataTable dentro de la colección de Tables del DataSet.3.Tables["Categorias"]. 4. la información es volcada sobre un objeto del tipo matriz de DataRow. igual que cuando guardamos el DataTable. accedemos por mediación de la colección Tables.Tables["Empleados"].Tables["Empleados"]. En este ejemplo obtenemos todas las filas del DataTable Empleados cuyo valor de IdCategoria sea 2. si sabemos que el DataTable Empleados es el cero dentro del índice.3. //A Continuación aplicamos la relación.Select("IdCategoria = 2"). Ejemplo: DataTable objTabla = objDataSet.Columns["IdCategoria"]. El método Select se comporta de una forma muy similar a la instrucción Select del T-SQL. DataRelation relacionClaves = new DataRelation("RelacionCategoria". Para obtener un DataTable que se encuentra dentro de un DataSet. En este ejemplo hemos accedido al DataTable Empleados y colocado una copia en objTabla. El método Select de los DataTable. En este caso.Tables[0].Columns["IdCategoria"]. Un ejemplo de aplicación del método Select sería: DataRow[] Filas = objDataSet. 4. Podemos obtener datos de un objeto DataTable usando el método Select. //Definimos dos objetos DataColumn con los nombres de las dos columnas //que vamos a relacionar. DataColumn ClavePrincipal = objDataSet.4.1. podemos recuperarlo de la siguiente forma: DataTable objTabla = objDataSet.Tables["Empleados"]. Capítulo 4.4. Por ejemplo. A continuación creamos las relaciones que pudieran existir entre las distintas tablas dentro del DataSet. DataColumn ClaveForanea = objDataSet. objDataSet. Programación en ADO. Obtener objetos DataTable. tal y como podemos ver en este ejemplo: //Existe una columna que es la clave principal y otra que es la clave //foránea.Tables["Empleados"].ParentRelations.

Tables["Empleados"]. "NombreEmpleado DESC"). ModifiedOriginal La versión original de todas las filas modificadas.Select("IdCategoria = 2". incluyendo las agregadas. Otra posibilidad es obtener filas que cumplan un criterio basado en si han sido borradas. DataViewRowState. Otra posibilidad de ordenación sería: DataRow[] Filas = objDataSet. que es una modificación de los datos actuales. Página 33 .Select("IdCategoria = 2". Deleted Fila eliminada ModifiedCurrent La versión actual. NombreEmpleado ASC"). podemos incluir el parámetro Sort del método Select: DataRow[] Filas = objDataSet. Por defecto es ascendente. Otro ejemplo sería: DataRow[] Filas = objDataSet. incluyendo las filas que fueron eliminadas. null.Tables["Empleados"]. Las distintas posibilidades del DataViewRowState son: Valor de DataViewRowState Significado Added Fila nueva CurrentRows Las filas actuales. Este ejemplo ordena los resultados por la columna NombreEmpleado y de formas descendente (DESC). En este otro caso el resultado es ordenado primeramente por la columna ApellidosEmpleado de forma ascendente y por la columna NombreEmpleado de forma también ascendente.Added).Select("IdCategoria = 2 AND NombreEmpleado = 'Miguel Angel'"). OriginalRows Las filas originales.Tables["Empleados"]. por el NombreEmpleado igual a Miguel Angel. En este otro ejemplo. modificadas y sin modificar.Select(null. Programación en ADO.Tables["Empleados"]. modificadas u obtener sus valores originales. En este ejemplo obtiene todas las filas que fueron añadidas al DataTable. la búsqueda se realizar por el IdCategoria igual a 2 y. Si deseamos obtener los datos ordenados. "ApellidosEmpleado ASC. None Ninguno Capítulo 4. Para este punto disponemos del miembro enumerable DataViewRowState: DataRow[] Filas = objDataSet. Unchanged Fila sin modificar.

00" "Fecha < #1/31/2010#" “Fecha < „31/1/2010‟ Para el caso de las fechas. OR y NOT. Por ejemplo: "FirstName = 'John'" "Precio <= 50. Para las columnas que contienen valores de enumeración. Los valores de fecha se deben poner entre signos de libra esterlina (#) o comillas simples (') dependiendo del proveedor de datos. Por ejemplo. Por ejemplo: "EnumColumn = 5" Operadores Se permite la concatenación mediante operadores booleanos AND. El operador AND tiene precedencia sobre otros operadores. el valor se convierte en un tipo de datos entero. puede ocurrir que se den errores derivados del uso de los formatos de fecha en americano o en español. se deberá escribir "[Column#]". Ejemplo: Total * [Column#] Puesto que los corchetes son caracteres especiales. Se permiten decimales y notaciones científicas para los valores numéricos. pero para el caso de las fechas en español usamos las comillas simples. se debe utilizar una barra diagonal ("###BOT_TEXT###quot;) para crear un carácter de escape para el corchete. Si usamos notación americana usaremos las #. si forma parte de un nombre de columna. Programación en ADO.Parámetros y expresiones válidas en el método Select de los DataTable: Para utilizar una columna denominada "Column#" en una expresión. Se pueden utilizar paréntesis para agrupar cláusulas y forzar una precedencia. Por ejemplo: (LastName = 'Smith' OR LastName = 'Jones') AND FirstName = 'John' Capítulo 4. Valores Definidos por el Usuario Los valores definidos por el usuario se pueden utilizar en expresiones para compararlos con valores de columnas. una columna denominada "Column[ ]" se escribirá: Total * [Column[\]] Sólo se debe crear un carácter de escape para el segundo corchete. Página 34 . Los valores de cadena se deben escribir entre comillas sencillas.

Por ejemplo. Por ejemplo: "ItemName LIKE '*product*'" "ItemName LIKE '*product'" "ItemName LIKE 'product*'" No se permiten los caracteres comodín en mitad de una cadena. los caracteres de corchete se deben establecer como caracteres de escape entre corchetes (por ejemplo. El valor de la propiedad CaseSensitive de la clase DataSet determina si en las comparaciones de cadenas se distingue entre mayúsculas y minúsculas. no se admite 'te*xt'. Al crear expresiones de comparación. Sin embargo. Programación en ADO. se permiten los siguientes operadores: También se admiten los siguientes operadores aritméticos en las expresiones: Operadores de Cadena Para concatenar una cadena se utiliza el carácter +. al final de un modelo o bien al comienzo de un modelo. dichos caracteres se deben establecer como caracteres de escape entre corchetes ([]). Se permite un carácter comodín al comienzo y al final de un modelo. se puede reemplazar ese valor por la propiedad CaseSensitive de la clase DataTable. Caracteres Comodín Tanto * como % se pueden utilizar indistintamente como caracteres comodín en una comparación LIKE. Si la cadena de una cláusula LIKE contiene un carácter * o %. Capítulo 4. Si hay un corchete en la cláusula. Página 35 . [[] o []]).

Página 36 . Por ejemplo: Avg(Child. Por ejemplo.Quantity) Agregados Se admiten los siguientes tipos de agregados: Normalmente los agregados se llevan a cabo en las relaciones. se debe incluir la referencia a la columna secundaria en una función de agregado. Se puede hacer referencia a una columna de una tabla secundaria en una expresión anteponiendo Child al nombre de la columna.Precio hace referencia a la columna denominada Precio de la tabla primaria. la sintaxis es: Child(RelationName). dado que las relaciones secundarias pueden devolver varias filas. Sum(Child. Por ejemplo. como se ha descrito en Referencia a relaciones primarias y secundarias.Referencia a Relaciones primarias y secundarias Se puede hacer una referencia a una tabla primaria en una expresión anteponiendo Parent al nombre de la columna. si una tabla tiene dos tablas secundarias denominadas Customers y Orders. Sin embargo. para crear un resumen de cifras de una columna denominada "Price": Sum(Precio) Ver: Uso DataTable-DataSet Capítulo 4.Precio) devolvería la suma de la columna denominada Precio de la tabla secundaria. Por ejemplo. Se crea una expresión de agregado mediante una de las funciones enumeradas anteriormente y una columna de una tabla secundaria. Si una tabla tiene varias tablas secundarias. Programación en ADO. la referencia sería la siguiente: Avg(Child(Customers2Orders). Por ejemplo. y el objeto DataRelation se denomina Customers2Orders.Precio) Un agregado también se puede realizar en una sola tabla.Precio) Avg(Child(Orders2Details). Parent.

como por ejemplo. La filosofía de diseño de ADO . este a su vez. Cuando solicitamos datos.NET (ActiveX Data Object) ADO. Al final. Esto significa que la aplicación se conecta sólo cuando necesita realizar una tarea con la base de datos.NET es una tecnología de Mircrosoft que sustituyo a DAO (Data Access Object). Todo acceso a la base de datos se realiza desde ADO . ADO . Una vez que hemos realizado operaciones con esos datos.NET y. Página 37 .NET permite restablecer la conexión con la base de datos y actualizar los datos que estábamos manejando.5. a RDO (Remote Data Object) y a la versión anterior.NET es el XML. estos son almacenados en memoria cache. El formato de transferencia de ADO .NET trabaja como intermediario entre nuestra aplicación y la base de datos.NET por mediación de órdenes. En realidad trabajamos sobre una copia de los datos originales. Programación en ADO. estando el resto del tiempo desconectado del Servidor de Bases de Datos. que son objetos que encapsulan sentencias de SQL o procedimientos almacenados. ya que permite disponer de un mayor número de conexiones posibles. Introducción ADO. HTTP.NET es evitar el mantener activa permanentemente una conexión con la base de datos. El programa nunca ve directamente los datos. llamada simplemente ADO. Esquema del modelo de trabajo de ADO Capa de Presentación Capa Lógica Negocio Capa de Datos Conjunto de Datos Aplicación Bases de Datos Windows Aplicación Consola Aplicación WEB Adaptador Conexión de Datos Adaptador Conexión de Datos Capítulo 4. esto repercute muy beneficiosamente en el uso del Servidor. sino que le son suministrados por ADO . el modelo de ADO . aunque también pude trabajar en modo permanentemente conectado. lo que permite trabajar sobre los datos sin tener una conexión abierta. devuelve la información a la base de datos cuando el programa así lo requiere. Un fichero XML es un fichero de texto que puede ser enviado con cualquier protocolo.4.

Responsable de las órdenes o comandos sobre la base de datos. proporciona acceso a las clases que permiten trabajar con ADO. Lee una secuencia de datos de sólo avance y sólo lectura desde un origen de datos. es decir. Command. Espacio de nombres: System. . DataReader. DataAdapter. Lector de los datos. Página 38 .Esquema de los modos de trabajo de ADO Aplicación DataSet Proveedor de Acceso a Datos DataReader Command DataAdapter Connection Leyenda: Modo Conectado Base de Datos Modo Desconectado Componentes de ADO . . Capítulo 4. Algunos de los componentes que incorpora son: . Programación en ADO. Responsable de realizar las conexiones con la base de datos.NET.Data.Data Los objetos de ADO . Connection. Representa un conjunto de comandos SQL y una conexión de base de datos que se utilizan para rellenar el objeto DataSet y actualizar el origen de datos. .NET.NET pertenecen al espacio de nombres System.

SQL Server. En algunas circunstancias. El System. El Proveedor de datos El proveedor de datos es el responsable de crear una comunicación entre la aplicación y el origen de datos. OLE DB. Cualquier versión del Sql Server 7. o para actualizar esos datos en el origen. así como de suministrar todos los componentes necesarios para trabajar con los datos. Oracle.Data. El System. Cada Servidor de Datos usa su propio proveedor de datos. podemos acceder a la mayoría de los Servidores de SQL que hay en el mercado. o superior. Se utiliza en ambos sentidos. .Data. Para el caso de MySQL. para recuperar datos de un origen. Así encontramos para: . Programación en ADO. Página 39 . podemos usar ODBC.OracleClient . El System.Data. Todos estos objetos se analizarán más adelante cuando tratemos los dos modos de acceso de ADO: Conectado y Desconectado. ODBC. podemos encontrarnos que no existe un proveedor nativo y por tanto debemos de usar uno genérico.Odbc . El System.Data. es decir. pero es necesario acudir al fabricante para que nos Capítulo 4. también llamado proveedor de datos nativo.SqlClient.OleDb Por mediación de ODBC y OLE DB. Esquema del Proveedor de Datos El Proveedor de Datos Connection DataAdapter Transaction SelectCommand InsertCommand Command UpdateCommand Parameters DeleteCommand DataReader Cada proveedor tiene su correspondiente espacio de nombres asignado.

suministre el proveedor de datos nativo.Catch. se definirán.aspx Dentro del proveedor de datos. por mediación de propiedades. obviamente se cerrará si no se utilizará más adelante. ADO puede trabajar tanto en modo permanentemente conectado a la base de datos. 5. 3. La conexión debe de cerrarse lo antes posible. Programación en ADO. A continuación vemos en detalle los dos modos de trabajo de ADO. usamos OleDbConnection. De todas formas. Normalmente se realizarán distintas pruebas para verificar el nivel de respuesta de la aplicación. Todas las conexiones hay que realizarlas bajo Try. La mejor elección del modo de trabajo dependerá del entorno y las necesidades y requerirá un estudio detallado de cada situación. Como hemos visto. disponemos del objeto Connection. Capítulo 4. Nunca se debe dejar una conexión sin cerrar. si queremos conectar con SQL Server usamos el objeto SqlConnection. 2. Microsoft facilita en el siguiente enlace proveedores de datos por terceros: http://msdn. etc. todas las variables que se puedan definir antes de la conexión. el password de conexión. Así.. Este objeto es común tanto para el modo Conectado como para el modo Desconectado. que permite realizar la conexión. ya que estos se comportan mucho mejor que un proveedor genérico como es ODBC. La apertura de la conexión es lo último que hay que hacer. para conectarnos a Access. 4. la base de datos que se conecta. Para un óptimo rendimiento de la aplicación. especificar el id de usuario. En función del proveedor de datos que estemos usando cambia el objeto Connection.com/en-us/data/dd363565. lo ideal es usar el proveedor nativo del Servidor de Base de Datos con el que vamos a trabajar. Recomendaciones a la hora de realizar las conexiones: 1. El objeto Connection permite. como en modo desconectado (conecta sólo cuando es necesario). Página 40 ..microsoft. Es decir. Su función es proveer de los métodos y propiedades necesarios para realizar una correcta conexión con el origen de datos.

varía en función del Servidor de Datos.4.6. tenemos OracleCommand. Ejemplo: Uso ADOConectado-SQL y Uso ADOConectado-ACCESS Capítulo 4. para Sql Server tenemos SqlCommand y para Oracle.0. que al igual que Connection. Para OleDb tenemos OleDbCommand.4. Así. OleDbCommand objComando = new OleDbCommand(Consulta. Conexion). Una vez ejecutado un objeto Connection.. El modo conectado tiene un esquema de trabajo que podemos ver en el siguiente esquema: Esquema ADO Conectado Aplicación Origen Datos DataReader Command Connection Representación en código del esquema string Conexion = "Provider=Microsoft. Página 41 .\.ExecuteReader().. tenemos OdbcCommand. En su lugar podemos usar el objeto DataReader. OleDbDataReader Informacion = objComando. disponemos de un objeto concreto para cada origen de datos. podemos ejecutar comandos de SQL por mediación del objeto Command.Jet.\.". SqlDataReader para Sql Server.\empresa.mdb. El modo ADO Conectado El modo conectado mantiene la conexión con el servidor." + "Data Source=C:. apellidos FROM empresa". OleDbConnection objConexion = new OleDbConnection(Conexion). Programación en ADO. Al igual que para los objetos anteriores. string Consulta = "SELECT nombre. OdbcDataReader para ODBC y OracleDataReader para Oracle. Muchas veces no es necesario almacenar los datos leídos en un Conjunto de Datos (DataSet). tenemos OleDbDataReader para OleDb. ya que esta opción puede consumir mucha memoria. mientras la parte de la aplicación que ha accedido a los datos este activa. pero la trae en pequeñas unidades de trabajo que descarga la memoria de la máquina cliente. Este objeto.OLEDB. para ODBC. vuelca directamente la información a la aplicación.

// ExecuteReader hace la consulta y devuelve un OleDbDataReader OleDbDataReader objLector = objOrden. if (objLector.ExecuteReader(). apellidos FROM Empleados".Open().". Se utiliza el método Read del objeto DataReader para obtener una fila a partir de los resultados de una consulta.. // Abrir la base de datos objConexionOleDb.0. Programación en ADO. Para poder cargar el DataReader. Es decir. por su nombre (como hemos realizado en el ejercicio anterior – nombre y apellidos-) o por su referencia numérica. La propiedad HasRows del DataReader permite saber si existen filas en el objeto DataReader después de ejecutar el Command.\empleados.\.OLEDB. El Modo Conectado usa un objeto del tipo DataReader para recuperar un conjunto de datos desde la base de datos y posteriormente los almacena en un buffer intermedio (aunque los datos no son almacenados en ninguna memoria cache).mdb. Data “ + “Source=C:. Método Read..Read()) // siguiente registro MessageBox. Un DataReader necesita obligatoriamente un objeto Command para poder trabajar. Capítulo 4.4.HasRows) { while (objLector. OleDbConnection objConexionOleDb = new OleDbConnection(objConexion). OleDbCommand objOrden = new OleDbCommand(strConsulta. aplicamos el método ExecuteReader() del objeto Command: DataReader = Command. Página 42 . podemos acceder a cada columna o campo contenido en el DataReader. objConexionOleDb). El resultado de la ejecución de un objeto Command es utilizado por el DataReader para crear ese buffer intermedio.Jet.Show(objLector["nombre"] + " " + objLector["apellidos"]). } // Llamar siempre a Close una vez finalizada la lectura objLector. Para obtener su contenido.Close().ExecuteReader(). en el ejemplo.\. HasRows // permite saber si hay registros cargados desde la consulta.ExecuteReader(). Ejemplo: // Crear la conexión con la base de datos Empleados de //Access string objConexion = "Provider=Microsoft. // Usamos el método Read para acceder a los datos. //Crear una consulta para la base de datos string strConsulta = "SELECT nombre.

GetGuid. éstos no estarán disponibles hasta que se cierre el DataReader. que permite recuperar información sobre el esquema actual de datos. GetDouble. Si se utilizan los métodos de descriptor de acceso con tipo. no se podrá ejecutar ningún comando para el objeto Connection hasta que se cierre el DataReader original.WriteLine(columna. Página 43 . hay que indicar la referencia numérica de la columna a la que nos estamos refiriendo. Un DataReader dispone del método GetSchemaTable(). el uso de GetString da un error. foreach (DataRow fila in obj. Programación en ADO. El resultado lo devuelve en un objeto del tipo DataTable. por objLector[0]. Los DataReader.Columns) { Console.ColumnName + " = " + fila[columna]). se recude el número de conversiones de tipo necesarias para recuperar el valor de una columna. } } Capítulo 4. es necesario llamar al método Close() para su cierre. De todas formas. por tanto. dando por supuesto que se conoce el tipo de datos subyacentes. Obsérvese que entre los paréntesis del método de descriptor de acceso con tipo GetString. etc.podemos sustituir objLector[“nombre”].).Show(objLector.GetString(0) + " " + objLector. rellenando cada fila por cada una de las columnas del conjunto de datos.GetSchemaTable(). Para el ejemplo anterior. podemos sustituir la línea que escribe los datos por esta otra: MessageBox. GetString.Rows) { foreach (DataColumn columna in obj. Un DataReader usa de forma exclusiva el objeto Connection.GetString(1)). Ejemplo: DataTable obj = objLector. ColumnName es el nombre de la propiedad y el valor de la Columna es el de la propiedad. incluida la creación de otro DataReader. Esto es porque la columna que se encuentra en la posición 0 del DataReader es la de Nombre. GetInt32. Cada Columna de una fila de la tabla de esquemas está asociada a una propiedad de la columna que se devuelve en el conjunto de datos. cuando se han terminado de utilizar. ya que si el objeto Command contiene parámetros de salida o valores devueltos. Hay que tener cuidado si el campo al que se accede es null. el mejor rendimiento se consigue usando los métodos que dispone el DataReader y que permiten tener acceso a los valores de las columnas en sus tipos de datos nativos (GetDateTime.

Parameters. Pero si lo que deseamos es realizar otros comandos que necesitan parámetros.Integrated Security=True. Por ejemplo: string Nombre = “ ‘Antonio’ “.database=Empleados"). string str = "INSERT INTO empleados(NombreEmpleado. ApellidosEmpleado)” + "VALUES(@Nombre. etc. Ejecutar un comando insertar en ADO Conectado Cuando hacemos consultas usando el objeto Command de ADO Conectado. lo que devuelve es un valor de tipo int con el número de filas afectadas por el comando ejecutado. SqlCommand myCommand = new SqlCommand(str. myConn). aunque pueda parecer práctica no se debe de realizar nunca. Como podemos ver." + Apellidos + ". Esta última forma. menos académica. IdDepartamento. tenemos que utilizar la colección Parameters del objeto Command y luego podemos ejecutar el comando pero con el método ExecuteNonQuery.AddWithValue("@Nombre". Otra posibilidad. Las variables como Nombre. del objeto Command. nos permite cargar en una sola acción el parámetro y su valor. Programación en ADO. Capítulo 4. Página 44 . "Pedro"). contiene la cadena de SQL que se tiene que ejecutar en el servidor. le suministramos la sentencia como un string y a continuación ejecutamos el comando con ExecuteReader. En la cláusula “values” aparecen variables de SQL que son las que guardarán el valor pasado con la propiedad. @Apellidos)". Apellidos. El método AddWithValue. EmpleadoActivo.AddWithValue("@Apellidos"." + Activo + ". "López Ruiz"). ApellidosEmpleado. myCommand." + Cate + ")". Para el caso de ExecuteNonQuery." + Depar + ". myConn). es pasar los valores a la sentencia como podemos ver en este otro ejemplo: string str2 = "INSERT INTO empleados(NombreEmpleado. myCommand. NOTA: Esto permite un fallo de seguridad conocido como SQL inyectado. str. ExecuteReader devuelve en un objeto DataReader el resultado de la consulta.Parameters. SqlCommand myCommand = new SqlCommand(str2. Parameters. Ejemplo: SqlConnection myConn = new SqlConnection("Data Source=PORTATIL\SQLEXPRESS. como ocurre en el caso del comando Insert que necesita una lista con los valores a insertar. deben de contener el valor entre comillas simples." + DNI + ". IdCategoria) " + "VALUES(" + Nombre + ". DNIEmpleado.

Programación en ADO. que tomando dos parámetros de entrada: Codigo y Precio. Lo primero que tenemos que saber es que en ADO es necesario crear tanto los parámetros de entrada como el parámetro de salida con el mismo nombre que tienen en el procedimiento almacenado. la mayor parte de los accesos a los datos no se suelen realizar por mediación de instrucciones ejecutadas directamente.Output. objComando.Add(new SqlParameter("@result". "167")). cuando queremos invocarlo llamamos a la colección Parameters[0]. Aquí vamos a diseñar un ejemplo que accede a un procedimiento almacenado llamado ActualizaPrecios. En los parámetros de entrada especificamos el valor que van a tener cuando se ejecute el procedimiento. Hay que indicar que el objeto que aparece en este ejemplo. es un objeto del tipo Connection que realiza la conexión con la base de datos.StoredProcedure. Sabemos que está en la posición cero.Parameters. introducimos los tres parámetros: uno de salida (result) y dos de entrada (Codigo y Precio). objComando. Dado que el primer parámetro declarado en el objeto Command ha sido el valor de salida. El procedimiento devuelve con un parámetro de salida llamado result.Int)).Parameters. Ejecutar un procedimiento almacenado con parámetros de salida. Por mediación de la propiedad CommandText introducimos el nombre del procedimietno almacenado. Observamos que por mediación del miembro enumerado SqlDbType.Parameters. objComando. Capítulo 4.CommandType = CommandType. Debido a temas de rendimiento del servidor de SQL. actualiza el precio para el Id de libro facilitado por código. Ejemplo Uso ProcedimientoAlmacenado SqlCommand objComando = objConexion. Página 45 . En principio sólo será una (el Id del libro es Clave Primaria y por tanto no acepta repeticiones).ExecuteNonQuery(). objComando. objComando. especificamos en el parámetro de salida el tipo correspondiente al valor devuelto por el procedimiento almacenado. el número de filas afectadas. sino que se utilizan procedimientos almacenados.CreateCommand().Direction = ParameterDirection. por mediación de la colección Parameters del objeto Command.Add(new SqlParameter("@Precio".CommandText = "actualizaprecios". A continuación y. "1")).Parameters[0].Add(new SqlParameter("@Codigo". SqlDbType. objComando. objConexion. objComando.

El modo ADO Desconectado La norma general es usar un adaptador por cada origen de datos y un solo objeto DataTable del conjunto de datos.7.4. forma parte importante del modelo de ADO Desconectado. DataAdapter y DataSet. las filas pueden ser relacionadas con otras tablas. Por mediación del objeto DataTable puede contener en su interior múltiples tablas compuestas por campos de distintos tipos. a través de claves exteriores y de relaciones complejas que imponen restricciones de datos Capítulo 4. Página 46 . La Clase DataSet Si bien el DataSet no forma parte del ADO como tal. Como tablas que son. Programación en ADO. ya que podemos usar un DataSet sin necesidad de conectarnos a una base de datos. para trabajar con ADO desconectado necesitamos los siguientes objetos: Connection. al igual que si estuviéramos en SQL. Siguiendo la estructura explicada anteriormente. Jerarquía de la clase DataSet DataTable DataRelation DataTable Datacolumn Datacolumn DataRow DataRow Un DataSet es una base de datos de memoria interna. Esquema ADO Desconectado Origen de Datos DataAdapter Conjunto de SelectCommand Aplicación InsertCommand Conexión Datos DeleteCommand UpdateCommand El Modo Desconectado.

eliminar y consultar filas contenidas en un DataTable. Programación en ADO. En un DataSet se pueden utilizar métodos para buscar el contenido de las tablas que lo componen. ADO Desconectado. Podemos ver un ejemplo de cómo se crea un DataSet de forma dinámica. En este ejemplo hemos diseñado una simple tabla que contenía un campo clave y hemos realizado una búsqueda sobre la tabla. al igual que hacen los campos Identity en SQL Server. se lanzará de forma automática la siguiente ventana: Capítulo 4. por mediación del objeto DataTable. Evidentemente un DataSet puede guardar información en formato XML y en un formato binario propio para ADO . En este caso vamos a utilizar a modo de ejemplo los componentes disponibles en la barra de herramientas. Si introducimos un objeto SQLDataAdapter (realizaremos la conexión contra SQL Server). Los DataTable permiten asignar valores automáticos según se insertan filas en la tabla. Página 47 . Además se puede tratar un DataSet como si fuera un documento XML y realizar consultas XPath.padre/hijo. Ejemplo Uso DataSet En el ejemplo de Uso DataSet podemos comprobar como el propio DataSet es capaz de guardar tablas.Net. así como las opciones de agregar. como si se tratase de un gestor de SQL. Ejemplo utilizando la interfaz gráfica de Visual Studio. Empezamos con el objeto SQLDataAdapter.

Aparecerá una pantalla explicando que todas las instrucciones para el adaptador se han realizado de forma correcta. disponemos de un asistente en el botón “Generador de Consultas”. Capítulo 4. Página 48 . En la imagen superior. Nos permite especificar cuatro orígenes distintos: tres en modo nativo (el de Access es OleDb) y uno en modo ODBC. A continuación seleccionamos la Base de Datos de la lista desplegable. pulsamos Aceptar. podemos definir todas las propiedades necesarias para poder realizar una conexión. seleccionamos “Usar Instrucciones SQL”. Pulsamos una conexión existente o nueva. Después. Origen de Datos SQL Server. Ahora sí. que es un estándar. en el menú “Elegir un Tipo de Comando”. habría que introducirlas en estas casillas). A continuación seleccionamos el nombre del Servidor donde se encuentran la Base de Datos que queremos consultar. Para facilitarnos la escritura de la sentencia de SQL. no el de “Finalizar”. permite definir en el mismo proceso el objeto SQLConnection. Después de seleccionar en la interfaz gráfica la instrucción. Devuelta a la ventana de “Elegir un Tipo de Comando”. pulsamos el botón “Siguiente”. El hecho de utilizar el SQLDataAdapter. Seleccionamos en la ventana “Agregar Conexión”. pulsamos el botón de “Finalizar”. en el objeto DataAdapter. Se puede especificar un Origen de Datos distinto usando para ello el botón “Cambiar…”. Programación en ADO. En nuestro caso seleccionamos “Telefonos” (utilizar el fichero de Generar la base de datos de teléfono en caso de no estar en el servidor). Especificamos “Usar Autenticación por Windows” (si el servidor requiriera conexión por usuario y contraseña de SQL Server.

del Visual Studio. Crear el Conjunto de Datos. A continuación seleccionamos la tabla Telefonos en la propiedad DataMember del DataGridView. En “Elegir origen de Datos”. Para ello usaremos en el menú “Datos”. que será el responsable de controlar y editar los datos que nos son suministrados por el DataSet. que la propiedad DataSource del DataGridView. la tabla o tablas de las que obtendremos los datos y hemos generado las instrucciones necesarias para ejecutar la consulta sobre la Base de Datos. En el DataGridView. seleccionamos en “Existente” el nombre del DataSet. Ahora debemos generar el resultado de la consulta. sea definida con el nombre del DataSet. sólo hemos definido la conexión. Esto hace. Página 49 . pulsamos sobre la flecha que aparece en la parte superior derecha del Grid. Capítulo 4. Hasta el momento. cuando lo seleccionamos. la opción de “Generar conjunto de Datos”. A continuación incorporamos al formulario un objeto del tipo DataGridView. En nuevo tecleamos el nombre que tendrá el DataSet que utilizaremos para rellenar los datos (ver imagen de la derecha) y pulsamos aceptar. Programación en ADO. “dataSetTelefonos1”. Si lo que queremos es incluir una consulta en una nueva tabla (DataTable) dentro de un DataSet ya creado. según el ejemplo. (ver imagen de la derecha) seleccionamos.

Si bien el entorno de diseño es muy cómodo de usar. En su lugar desarrollaremos clases cuya finalidad sea generar los datos desde la Base de Datos. dataSetTelefonos1. es muy cómodo para el usuario modificar directamente los datos en un DataGridView y debemos dar esa posibilidad al usuario. MessageBox. no es muy buena idea usar los asistentes para su desarrollo.Update(dataSetTelefonos1). podemos modificar el contenido de los datos obtenidos con el DataAdapter que se encuentran en el DataGridView. pero estos no se actualizaran en la Base de Datos hasta que no se lo indiquemos. en el modelo de programación de tres capas. incorporamos un botón al formulario que servirá para mostrar los datos en el Grid y en su evento click. En el caso de las conexiones con ADO. tecleamos el siguiente código. escribiremos este código en otro botón que utilizaremos para que el usuario cuando quiera pueda guardar: // Primero pregunta si se han producido cambios en el // Conjunto de Datos contenidos en el DataSet. Si no queremos que se pueda modificar. para //que cargue los datos en el DataSet.HasChanges()) { if (MessageBox.Fill(dataSetTelefonos1). permite modificar los datos que se encuentran en las filas. El ejemplo que viene a continuación tiene como finalidad desarrollar las cuatro instrucciones básicas para trabajar con datos desde ADO Desconectado: Select. //Después llamamos al adaptador y a su método Fill.Show("Datos Actualizados"). ya que estos acaban en la Capa Presentación que es la ventana. Programación en ADO. debemos de poner su propiedad ReadOnly a true. la parte de conexión a Bases de Datos. if (dataSetTelefonos1. } } ADO Desconectado usando código en lugar del asistente. Página 50 . Pero a veces. Insert. Para guardar los datos. para ello. "Modificar Datos".Clear(). sqlDataAdapter1.Show("Quiere Modificar los cambios en la Base de Dato (Sí o No)". //Limpia cualquier contenido que tuviera. Ahora falta cargar el DataGridView con los datos disponibles. MessageBoxButtons. Un DataGridView.Yes) { sqlDataAdapter1. Update y Capítulo 4. En el modo ADO Conectado ya vimos algunos ejemplos de cómo desarrollarlo en modo código. es sin lugar a dudas Capa Lógica de Negocio o Intermedia. Por tanto.YesNo) == DialogResult.

Text. SqlCommandBuilder RestoSQL = new SqlCommandBuilder(Adaptador). Adaptador. SqlDataAdapter Adaptador = new SqlDataAdapter("SELECT * from categorias". a continuación. FilaNueva[1] = textBox1.Rows.GetInsertCommand().Fill(DatosDataSet). Adaptador. insertar una fila en el DataTable.Delete. para posteriormente actualizar todos los datos con el método Update del adaptador.Text. para construir las otras tres instrucciones.InsertCommand = RestoSQL.Update(DatosDataSet). en lugar de utilizar el objeto Command. cuya finalidad es añadir las columnas y columna clave necesarias para operar cuando no existan un DataTable y DataSet que lo contenga.GetUpdateCommand(). a partir del adaptador que tiene fijada la instrucción Select. Para ello. El resto es llamar al método Fill del adaptador para que cargue el DataSet con la tabla generada por la instrucción Select y. Página 51 . En nuestro caso.NewRow(). GetDeleteCommand y GetUpdateCommand. Programación en ADO.GetDeleteCommand(). usaramos el objeto CommandBuilder: string Cadena = @"Data Source=PROFESOR\SQLEXPRESS. Conexion). En este ejemplo.Tables[0].Add(FilaNueva). FilaNueva[2] = textBox2.MissingSchemaAction = MissingSchemaAction. DataRow FilaNueva = DatosDataSet.Initial Catalog=Empresa. usamos los métodos GetInsertCommand. Adaptador.Tables[0]. Adaptador. Adaptador. Como podemos ver el SqlCommandBuilder recibe como parámetro de entrada (usamos el constructor) al propio adaptador y. DatosDataSet. DataSet DatosDataSet = new DataSet().Integrated Security=True". es necesario crear antes las instrucciones que generar el DataSet y por supuesto el DataTable. Adaptador. cabe destacar la propiedad MissingSchemaAction.UpdateCommand = RestoSQL. SqlConnection Conexion = new SqlConnection(Cadena). Capítulo 4.DeleteCommand = RestoSQL.AddWithKey.

usando para ello dos botones (siguiente. "Personas. “NombrePersona").4. Para poder enlazar una matriz de tipo List.MovePrevious(). tbxNombre.DataBindings.DataBindings. Su funcionamiento permite enlazar universalmente todos los controles de formularios Windows a orígenes de datos muy diversos.Nombre"). private BindingSource Navegador = new BindingSource(). EventArgs e) { Navegador. Simplifica la conexión facilitando la actualización del contenido. la notificación de cambios.8. EventArgs e) { Navegador. tbxApellidos. Asignar a su propiedad DataSource una lista. Previamente se ha asignado al DataBinding el DataSet (DataSetPersonas). anterior): private List<Persona> MatrizPersonas = new List<Persona>(). A continuación diseñamos los eventos click de los dos botones: private void btnSiguiente_Click(object sender. Usar el método Add para añadir un elemento al componente BindingSource. Ejemplo Uso BindingSource. Navegador. el origen de datos. "ApellidosPersona"). “Personas.Add("Text". Capítulo 4. filtrado y actualización.Nombre”. //Asignamos al BindingSource. Página 52 . objeto o un tipo. a un objeto DataBinding y posteriormente mostrar todos los datos de esa matriz en dos TextBox llamados: tbxNombre y tbxApellidos.DataBindings. Personas es la tabla que contiene el DataSet y Nombre es el campo de la tabla. Programación en ADO.Add("Text".Add("Text". Navegador. DataSetPersonas. . //Vinculamos las cajas de texto al control BindingSource.DataSource = MatrizPersonas. El origen de datos subyacente se fija a través de uno de los siguientes mecanismos: .MoveNext(). } Si en lugar de asignar el DataBinding para controlar una matriz quisiéramos hacerlo para acceder a un conjunto de datos almacenado en un DataSet: tbxNombre. etc. } private void btnAnterior_Click(object sender. Navegador. Se incluye la navegación. Control BindingSource Es un objeto que hace de intermediario entre el control y el conjunto de datos. ordenación.

anterior. Programación en ADO. cuyo nombre es el que le hemos suministrado pero al final le añade un 1 (objDataSetEmpleados1). al cual le asignamos a su propiedad BindingSource. 5. Incluimos un objeto BindingNavigator. provee de varias funcionalidades para trabajar con conjuntos de datos. Ejemplo: Uso BindingNavigator Es un control basado en un objeto ToolStrip que incluye los componentes mencionados anteriormente. Para ello podemos utilizar el evento Load de la ventana en la cual introducimos las siguientes líneas: objDataSetEmpleados1. Estas funciones son: Primer registro. Ver figura. ApellidosEmpleado. Necesita de un objeto BindingSource para funcionar. Página 53 . el cual se vincula al objeto BindingNavigator por mediación de su propiedad BindingSource.4. Incluimos en el formulario los Textbox y label que contendrán la información. Seleccionamos el origen de datos y definimos la consulta que se realizará sobre la base de datos empleados. Lo Llamamos objDataSetEmpleados. Es necesario cargar el DataSet Previamente. llamado BindingSource1. que permite realizar funciones de navegación por el conjunto de datos. al cual le asignamos a su propiedad DataSource. 4. Vamos al menú Datos y generamos el Conjunto de Datos. Automáticamente genera un objeto. 7. A continuación seleccionamos la propiedad Text del DataBindings de cada Textbox y le asignamos el campo de la tabla que se mostrará. Nombre del Departamento Empleado y Nombre de la Categoría del Empleado. el objeto objDataSetEmpleados1 y a su propiedad DataMember. A partir de la versión 2005. Usamos para ello los campos contenidos en el BindingSource1. Microsoft incorporó un nuevo objeto llamado BindingNavigator. Práctica para crear un BindigNavigator: 1. el nombre de la tabla que va a manejar. Incluimos un objeto BindingSource. Creamos un objeto SQLDataAdapter. último. 3. siguiente. el objeto BindingSource1. número de registros totales en el conjunto de datos y posición actual. Capítulo 4. NombreEmpleado. Control BindingNavigator El control BindingSource. sqlDataAdapter1.Fill(objDataSetEmpleados1).9. Nuestro objetivo es obtener todos los registros de empleados mostrados por IdEmpleado. 6.Clear(). 2.

4.10. Programación avanzada en ADO
4.10.1. Transacciones. Operaciones de RollBack en la Base de
Datos. Espacio de nombres: System.Transactions

Microsoft incluyó a partir de Visual Studio 2005 un nuevo espacio de
nombres, System.Transactions, que proporciona una medio unificado por el
cual podemos acceder a recursos transaccionales, tales como la base de datos
SQL Server y la herramienta de Microsoft para realizar el manejo de colas de
mensajes MSMQ(Microsoft Message Queues).

Una de las ventajas de estas clases es que la aplicación puede utilizar
recursos locales de bajo coste durante una ejecución y luego
autoincrementarse utilizando operaciones distribuidas la próxima vez que se
ejecute, basadas en los recursos a los que el usuario final accede.

El nuevo sistema de transacciones proporciona dos formas de hacer uso
de transacciones como un cliente: explícitamente, utilizando derivados de la
clase Transaction e, implícitamente, usando los ámbitos de transacciones.

4.10.1.1. Transacciones Explícitas.

Lo primero a tener en cuenta es que es necesario agregar como
referencia al proyecto el espacio de nombres System.Transactions. Este
espacio de nombres nos va a permitir usar la clase CommitableTransaction,
que alberga los métodos Commit y Rollback, utilizados para ejecutar la
transacción o deshacer la transacción. La operación queda vinculada a la
conexión, lo que significa que estos dos métodos sólo actúan sobre la conexión
a la que son vinculados. Ejemplo Uso TransaccionesExplicitas.

Como podemos ver en el ejemplo, si el borrado de las filas que cumplen
la condición se encuentra con el método Rollback, a pesar de que al ejecutar el
Comando con el método ExecutenonQuery a provocado el borrado, la
operación es anulada. Por el contrario si colocamos el método Commit, la
operación quedará ejecutada.

4.10.1.2. Transacciones Implícitas.

Microsoft recomienda realizar transacciones implícitas en lugar de
transacciones explícitas. La razón es que cuando se usan transacciones
implícitas, las operaciones desde múltiples administradores de recursos
pueden coexistir y operar unas con otras conforme a reglas predefinidas. Si
utilizamos transacciones implícitas, el código puede automáticamente alistarse
en una transacción primaria si existe o puede crear una nueva transacción si es
necesario. Mucho más útil es que si el código invoca a otro código que también
usa transacciones implícitas, la transacción implícita no se acomete hasta que
todas las transacciones anidadas decidan acometerse también.

Capítulo 4. Programación en ADO. Página 54

Las transacciones implícitas se realizan mediante la clase
TransactionScope., que tiene un uso muy parecido a using. El código que
reside dentro de un ámbito de transacción es intrínsecamente transaccional, y
accede a los administradores de recursos compatibles (como SQL Server
2005) desde dentro de un ámbito de transacción que utilizará transacciones
implícitamente. Si el código no llega a la línea donde se llama al método
Complete en un TransactionScope, la transacción creada dentro del ámbito se
eliminará y las transacciones primarias utilizadas a través del nido se
nominarán para eliminarse.

Ejemplo Uso TransaccionesImplicitas

Como podemos ver en el ejemplo, por mediación de un using hemos
declarado un ámbito de transacción implícita. Si el código dentro del using no
se llega a ejecutar en su totalidad porque hay un error, al no llegar a la
sentencia AmbitoTransaccion.Complete(), no se ejecutará ninguna orden que
se hubiera efectuado sobre el servidor de SQL.

Ejemplo Uso TransaccionesAnidadas
static SqlConnection objConexion;
private void btnAceptar_Click(object sender, EventArgs e)
try
{
using (TransactionScope scope = new TransactionScope())
{
using (objConexion = new SqlConnection("data
source=portatil\sqlexpress; initial catalog=Empresa;
Integrated Security=SSPI;"))
{
objConexion.Open();
for (int x = 1; x < 8; x++)
{
DeleteEmpleado(x);
}
}
scope.Complete();
}
}
catch (TransactionAbortedException)
{
MessageBox.Show("La operación ha sido abortada porque alguna
de las transacciones ha fallado");
}

}

private void DeleteEmpleado(int IdEmpleado)
{
using (TransactionScope scope = new TransactionScope())
{
SqlCommand objComando = objConexion.CreateCommand();
objComando.CommandText = "DELETE Empleados WHERE IdEmpleado = "
+ IdEmpleado.ToString();
objComando.ExecuteNonQuery();

Capítulo 4. Programación en ADO. Página 55

if (IdEmpleado < 5)
scope.Complete();
}
}

Quizás donde se pueda obtener un mayor rendimiento de las
Transacciones sea en la posibilidad de deshacer transacciones anidadas,
donde una de ellas provoca un error, o antes de que se ejecute se produce un
problema, y es necesario deshacer todo lo anterior.

En este ejemplo se crea un ámbito primario y en su interior un bucle que
se itera ocho veces; cada iteración intenta eliminar un empleado. El método
DeleteEmpleado eliminará todos los empleados excepto aquellos que su
IdEmpleado sea mayor de 5. Cada una de las iteraciones llamó al método
Complete de la transacción y se ejecutó perfectamente, pero si un Id sobrepasa
el valor de cinco, la transacción se anula. Cuando llamamos a un Id que es
mayor de cinco, la iteración falló ya que no se llamó a su método Complete y es
está iteración la culpable de que se provoque la llamada a la excepción
TransactionAbortedException. Esto tiene como consecuencia que el ámbito
primario se detenga y su método Complete nunca se cumpla.

4.10.2. Acceso Asíncrono a la Base de Datos.

Antes de Net Framework 2.0, si teníamos que acceder a una base de
datos con un tiempo de espera para realizar la consulta muy alto, y queríamos
que la aplicación no quedara suspendida, la llamada a la base de datos y la
consulta a ejecutarse se incluían en un método que era lanzado en segundo
plano (subprocesamiento).

A partir de Net Framework 2.0 Microsoft implemento métodos en muchos
objetos cuya finalidad es precisamente ejecutarse en hilos independientes, al
margen de la aplicación principal, para de esta forma liberar a nuestra
aplicación de procesos complejos.

El caso que vamos a tratar es el del objeto SqlCommand, que incorpora
a los métodos: ExecuteNonQuery, ExecuteReader y ExecuteXmlReader la
posibilidad de ejecutarse en segundo plano por mediación de Begin/End.

De esta forma podemos ejecutar los métodos en modo asíncrono,
mientras la aplicación sigue respondiendo a otros eventos que se pudieran
producir.

Ejemplo: Uso ADOAsincrono

Capítulo 4. Programación en ADO. Página 56

Object stateObject) El método asíncrono BeginExecuteReader. Se puede llamar al método EndExecuteReader desde este procedimiento de delegado o desde cualquier otra ubicación de la aplicación. Si no se activa este parámetro no lo permitirá y cuando se llame al método dará un error. Cuando termina la instrucción se debe de llamar al método EndExecuteReader para finalizar la operación y recuperar el valor de SqlDataReader devuelto por el comando. El parámetro Asynchronous Processing a true le indica al objeto ADO que esta conexión utilizará subprocesamiento múltiple. Asynchronous Processing=true. que devuelve una instancia de SqlDataReader que se puede usar para recuperar las filas devueltas. para que otras tareas puedan ejecutarse simultáneamente mientras se ejecuta la instrucción. pero hasta que el código ejecute la llamada al método EndExecuteReader correspondiente. Página 57 . El método BeginExecuteReader devuelve un valor inmediatamente. el objeto SqlCommand se bloqueará hasta que la ejecución termine. se puede pasar cualquier objeto en el parámetro stateObject y el procedimiento de devolución de llamada puede recuperar esta información mediante la propiedad AsyncState. El parámetro callback permite especificar un delegado de AsyncCallback al que se llama una vez finalizada la instrucción. no debe ejecutar ninguna otra llamada que comience una ejecución sincrónica o asincrónica con respecto al mismo objeto SqlCommand. Capítulo 4. devuelve un valor del tipo IAsyncResult. Como parámetros de entrada tenemos: CallBack. El método BeginExecuteReader inicia el proceso de ejecución asincrónica de una instrucción de Transact-SQL o de un procedimiento almacenado que devuelve filas. Además."). initial catalog=Empresa. Integrated Security=SSPI. En la sintaxis de la llamada que hemos realizado en el ejemplo tenemos: public IAsyncResult BeginExecuteReader (AsyncCallback callback. que se puede utilizar para sondear y/o esperar los resultados. Lo primero que podemos ver en el ejemplo es que la cadena de conexión incorpora un parámetro que permite ejecutar el comando en segundo plano: SqlConnection conn = new SqlConnection("data source=(localhost). Si se llama a EndExecuteReader antes de que finalice la ejecución del comando. el objeto declarado en una llamada asíncrona no puede utilizarse nuevamente hasta que la llamada finalice. Programación en ADO. Es decir. este valor también es necesario al invocar a EndExecuteReader.

Por ejemplo. Las excepciones se deben controlar en el procedimiento de devolución de llamada. Si se envía un comando de gran tamaño o un gran número de parámetros. Si se establece en 0. no se debe interactuar con el contenido de un formulario desde el procedimiento de devolución de llamada. insertar o modificar). Observe que el texto del comando y los parámetros se envían al servidor de forma sincrónica. las lecturas son asincrónicas. Ahora podemos establecer el tamaño del “lote de comando”. El ejemplo tiene tres partes muy concretas: la primera recupera los datos de la base de datos empresa. añade filas nuevas y elimina otras. En caso de que se tenga que actualizar el formulario. la obtención de valores sigue siendo sincrónica. el método devuelve un valor inmediatamente sin esperar una respuesta del servidor. Esto significa que las llamadas a Read pueden bloquearse si se requieren más datos y se bloquea la operación de lectura de la red subyacente. Aunque la ejecución de comandos es asincrónica. el adaptador de datos utilizará la máxima capacidad de lote disponible. Cuando esto ocurre. Si se determina un valor mayor de 1. se llama al método Update() del DataSet. este método puede bloquearse durante las operaciones de escritura. y por último. Ejecución de procesos por lotes En este caso vamos a utilizar un objeto DataSet para que sea el responsable de actualizar los datos en el SQL por mediación de un proceso por lotes. Programación en ADO. la segunda modifica filas existentes (las recuperadas en el DataSet). es muy importante que se controlen rigurosamente las interacciones entre los subprocesos desde las aplicaciones. usando el DataSet (ADO Conectado). es decir. Ejemplo: Uso ProcesoPorLotes Hay que tener en cuenta que los procesos por lotes tienen problemas de rendimiento cuando la cantidad de registros a modificar es muy grande. añade una sobrecarga innecesaria a la operación de actualización. ejecutarla y desplazarla al siguiente registro actualizado de la lista.NET. se debe volver al subproceso del formulario. 4. que ejecuta todas las filas de la tabla dentro del DataSet y le aplica la instrucción correspondiente a su estado (añadir. Todos los errores que aparecen durante la ejecución de la operación se inician como excepciones en el procedimiento de devolución de llamada. Página 58 . el adaptador de datos realizará su actualización por lotes que contiene el número de instrucciones Capítulo 4. Dado que el procedimiento de devolución de llamada se ejecuta desde un subproceso de fondo proporcionado por el motor en tiempo de ejecución de Microsoft .10. el crear una instrucción SQL. borrar.3. Una vez enviado el comando.

añadir y borrar datos de ellas. y nos permite modelar bases de datos relacionales con clases de . Podemos expresar consultas en los lenguajes de programación que se elijan y opcionalmente transformar/incrustar los resultados de las consultas en el formato que se quiera. así como actualizar.4.None.que previamente se indicó. Conocemos a este modelo de programación como “LINQ” que proviene de . La versión 3. para de esta forma manipular fácilmente los resultados.5 del .1. LINQ to SQL. y desarrollar herramientas que aporten intelisense y debugging cuando escriban código de LINQ.10. Para utilizar el diseñador hay que agregar al proyecto un nuevo elemento llamado: “Clases de Link a SQL” Usando ese diseñador LINQ to SQL se puede crear fácilmente una representación de la base de datos “Northwind”. LINQ to SQL es una implementación de O/RM(Object Relational Mapping -Mapeador de Objetos Relacionales-) que viene con la versión 3.10. Capítulo 4.NET Framework viene con librerías que habilitan LINQ sobre objetos.NET. 4.NET Language Integrated Query. Página 59 .NET Framework. El uso de Link En LINQ to SQL se puede utilizar la tecnología LINQ para tener acceso a las bases de datos de SQL igual que se obtendría acceso a una colección en memoria. 4. Los lenguajes habilitados para LINQ pueden aportar seguridad de tipos y chequeo en tiempo de compilación de las expresiones de consulta. Podemos consultar bases de datos con LINQ. Modelando bases de datos con LINQ to SQL: Visual Studio 2008 viene con un diseñador de LINQ to SQL que nos aporta una forma fácil de modelar y visualizar una base de datos como un modelo de objeto de LINQ to SQL. en todos los comandos implicados en el proceso por lotes.5 del .4. con el valor de UpdateRowSource. Los desarrolladores podemos usar LINQ con cualquier fuente de datos. Programación en ADO. El único tema importante es especificar la propiedad UpdateRowSource. LINQ soporta un modelo de extensibilidad muy rico que facilita la creación de operadores eficientes para fuentes de datos. XML y bases de datos.

El diseño de arriba define cuatro clases: Products. Programación en ADO. Categoryes. Esto implica que tendrá una propiedad “Categories” que es una colección de objetos Product con esa categoría. la clase Category de arriba tiene una relación de uno-a-varios con la clase Product. La clase Product entonces tiene una propiedad “Category” que apunta a una instancia de la clase Category representando la categoría a la que pertenece el producto. Se añadiran propiedades fuertemente tipadas a las entidades basándose en esto. Las propiedades de cada clase mapean las columnas de cada table en la base de datos. Esquema en el diseñador para la base de datos Northwing: Entendiendo la clase DataContext Cuando pulsamos el botón “save” del diseñador de LINQ to SQL.NET para representar las entidades y las relaciones de la base de datos que hemos modelado. Las flechas entre las cuatro clases de arriba representan las asociaciones/relaciones entre las diferentes entidades. Visual Studio generará clases . Son típicamente modeladas como relaciones primary-key/foreign-key en la base de datos. Por cada archivo añadido a nuestra Capítulo 4. Order y OrderDetail. Por ejemplo. Cada instancia de esa clase representa una fila en las tablas. La dirección de las flechas en el diseñador indican si la relación es uno-a-uno o uno-a-varios. Página 60 .

Programación en ADO. Esta clase es a través de la cual realizaremos las consultas a las entidades de nuestra base de datos. objProducto.SupplierID = 3.Categories.500 g pkgs. en la imagen de la izquierda podemos ver la clase DataClasses1DataContext. objIn. objPro.UnitPrice = 20. Esta clase tendrá propiedades que representarán a cada tabla que hemos modelado.Products. Capítulo 4. Además. podemos observar que ha generado una clase por cada una de las tablas que se han incorporado.QuantityPerUnit = "18 .ProductName. así como métodos para cada procedimiento almacenado que añadamos. podemos realizar las operaciones que vienen a continuación: Consultar Datos: DataClasses1DataContext objNort = new DataClasses1DataContext(). objProducto. Insertar Datos: DataClasses1DataContext objIn = new DataClasses1DataContext().UnitsInStock = 100. Modificar Datos: DataClasses1DataContext objNoMo = new DataClasses1DataContext(). var objProductos = from p in objNort.Products. objProducto. foreach (var obj in objProductos) Console. objProducto. Una vez diseñada la estructura.ReorderLevel = 0.UnitPrice = 100.InsertOnSubmit(objProducto). objProducto.CategoryName == "Beverages" select p. objPro. Products objProducto = new Products().ProductName == "Tofu"). objNoMo.Discontinued = false.solución por el diseñador LINQ to SQL también se generará una clase DataContext. objProducto. Products objPro = objNoMo.Products where p.Single(p => p.WriteLine(obj). que se ha generado a partir de las tablas que hemos incluido en la vista de diseño. objProducto.CategoryID = 2.SubmitChanges().". Por ejemplo. objProducto.UnitsInStock = 100. Página 61 .ProductName = "Jamón".

ProductName. Por ejemplo.//Guardamos los cambios en la base de datos objIn.SubmitChanges(). en archivos de configuración. LINQ to XML simplifica el código XML al proporcionar una experiencia de consulta similar a SQL.DeleteOnSubmit(objBorrar.First()).Products. Programación en ADO. Llamar a un procedimiento almacenado. Espacio de nombres System. La sintaxis es: DataClasses1DataContext objNoBo = new DataClasses1DataContext().Contains("Jam") select p. Borrar Datos: //Borrar una fila usando Linq a SQL. devuelve los pedidos realizados por el cliente. es necesario realizar un SubmitChanges para que los cambios realizados en la base de datos surtan efecto. proporcionan una funcionalidad similar. también podemos llamar a procedimientos almacenados. var objBorrar = from p in objNoBo. pasándole un Id de cliente (21). LINQ to XML es un método actualizado y rediseñado para la programación con XML. Linq a XML. salvo en el consultar. Con un poco de estudio. Igual que realizamos operaciones sobre la base de datos con el equivalente en Linq a las instrucciones de SQL. Página 62 . los programadores Capítulo 4. } Como hemos podido ver en cada uno de los ejemplos. etc. En este procedimiento. Aunque estas expresiones de consulta difieren sintácticamente de XPath. var objProcedimiento = objNoBo. y es compatible con expresiones de consulta LINQ.10.XML.4. en bases de datos. if (objBorrar.2. Proporciona capacidades de modificación de documento en memoria de Document Object Model (DOM). Al ser una colección podríamos usar un bucle foreach para recorrerla. objNoBo. En objProcedimiento almacena en una colección las filas devueltas por la ejecución del procedimiento llamado CustOrdersOrders.SubmitChanges(). 4.LINQ XML se ha adoptado ampliamente como un modo de dar formato a datos en diversos contextos.CustOrdersOrders(21). DataClasses1DataContext objNoBo = new DataClasses1DataContext(). se puede encontrar XML en la web.Count() > 0) { objNoBo.Products where p.

Puede consultar y modificar el documento. "info6"). denominado construcción funcional. cuyo funcionamiento y salvando el tema de las consultas en Linq. La capacidad de consulta de LINQ to XML es comparable en cuanto a funcionalidad (aunque no cuanto a sintaxis) a XPath y XQuery. new XElement("Root". La ventaja más importante de LINQ to XML radica en su integración con Language-Integrated Query (LINQ). XDocument srcTree = new XDocument(new XComment("TComentario"). new XElement("Child1". Una de las ventajas de usar LINQ. Se pueden usar expresiones de consulta de distintos dominios de datos simultáneamente. new XElement("Info8". "info7"). new XElement("Child3". new XElement("Child2". puede guardarlo en un archivo o serializarlo y enviarlo a través de Internet. LINQ to XML es una interfaz de programación XML en memoria y habilitada para LINQ que permite trabajar con XML desde los lenguajes de programación de . Página 63 . permite que los desarrolladores transformen fácilmente árboles XML de una forma a otra. Capítulo 4. new XElement("Info6". "data3"). que a su vez resulte más expresivo. es que permite escribir menos código. new XElement("Info7". "data4"). es similar a las clases aplicadas al modelo DOM en Net Framework. Ejemplo Uso LinqaXML: //Documento XML generado por XElement. que habilita un método eficaz para crear árboles XML. new XElement("Child2". "info8"))). Los objetos básicos serían XElement y XDocument. comprobación en tiempo de compilación y una compatibilidad mejorada con el depurador. "data2"). pueden aprender a escribir consultas concretas y eficaces en el lenguaje de programación que prefieran.NET Framework. "info5"). Se parece al Modelo de objetos de documento (DOM) en lo que respecta a la inserción del documento XML en la memoria. new XElement("Info5". Sin embargo.acostumbrados a Transact-SQL. Programación en ADO. La integración de Linq en Visual C# 2008 proporciona una escritura más rápida. Esta integración permite escribir consultas en el documento XML en memoria para recuperar colecciones de elementos y atributos. "data1"). compacto y eficaz. Este método. Otra ventaja es la capacidad de usar los resultados de la consulta como parámetros en constructores de objetos XElement y XAttribute. una vez modificado. LINQ to XML es diferente de DOM: proporciona un nuevo modelo de objetos más ligero con el que se trabaja más fácilmente y que aprovecha las mejoras de lenguaje de Visual C# 2008.

new XElement("Child". new XElement("Child". XElement xmlTree2 = new XElement("Root".WriteLine(doc). Console. Programación en ADO. from el in xmlTree1. UPDATE AS BEGIN SET NOCOUNT ON UPDATE dbo. cada 2 segundos.xml").Save("c:\fichero.xml").Empleados AFTER INSERT. new XElement("Child". Una solución podría ser utilizar un Timer para que ejecute un proceso de consulta al servidor. new XElement("Child".Elements() where ((int)el >= 3 && (int)el <= 5) select el). 6)). 3). Una alternativa sería crear un trigger y una tabla complementaria que nos permitiera realizar una consulta muy simple para comprobar el estado de un valor en esa tabla complementaria. Console. 1). por ejemplo.ReadLine(). new XElement("Child". XElement xmlTree1 = new XElement("Root". 4.WriteLine(xmlTree2). doc.StartsWith("data") select el)). Página 64 . podemos crear una tabla y trigger como el que tenemos en este ejemplo: CREATE TABLE dbo.TablaObservar SET Version = Version + 1 END GO Capítulo 4. Por ejemplo. Muchas veces nos podemos encontrar ante la necesidad de mantener permanentemente actualizados unos datos que hemos solicitado al servidor.10. from el in srcTree. pero a buen seguro. 5).5.Elements() where ((string)el). new XElement("Child".//Documento XML generado por una consulta.ReadLine(). que resulta muy costosa en recursos y tiempo en el servidor de datos si la consulta afecta a varias tablas y además es compleja. 2). Console.TablaObservar (Version int not null) GO CREATE TRIGGER Observar ON dbo. Esta solución puede ser fácil de implementar en código. xmlTree2.Element("Root"). 4). XDocument doc = new XDocument( new XComment("Esto es un comentario en la consulta"). DELETE.Save("c:\Elemento. Detectar Mensajes del Servidor de Datos en la aplicación. Console. new XElement("Root".

Read().ToString(). SqlDataReader Cambios = Comando. if (Cambios. Si los datos de la consulta sufren cambios. De todas formas este sistema sigue realizando consultas al servidor. baja o modificación) se modificara el valor del campo sumando uno al valor que tuviera. int Version = (int)Cambios[0]. if (UltimaVersion != Version) { this.Open) Conexion. } En este código realizamos una consulta que nos devuelve sólo la primera fila de TablaObservar. } } Cambios. Programación en ADO. CargarDatos(). Capítulo 4. Conexion). if (Conexion. Para ello. dispone de una clase llamada SqlDependency que se puede utilizar para poner en vigilancia una consulta. Desde una aplicación en . EventArgs e) { SqlConnection Conexion = new SqlConnection(Cadena). debe de permitir el Service Broker y tenerlo activado. Como previamente hemos guardado el valor que tenía en la variable UltimaVersion. el Servidor notifica esos cambios. Cuando se produce sobre la tabla una modificación. automáticamente detectará que los valores han cambiado y por tanto pasará a realizar una recargar de los datos que estamos visualizando en el DataGridView.Text = Version. Esa primera fila contiene el valor de Version. pero al fin y al cabo son cargas de trabajo para el servidor. UltimaVersion = Version.State != ConnectionState. el trigger programado suma uno al valor que tuviera ese campo. alta o baja. el servidor de Base de Datos. //Consulta que devuelve el valor del campo Version en TablaObservar SqlCommand Comando = new SqlCommand("SELECT TOP 1 Version FROM TablaObservar".Close().Net podemos configurar un Timer para que nos facilite en una consulta el valor del campo Version de TablaObservar: private void timer1_Tick(object sender. mucho menos pesadas y más rápidas. Este ejemplo crear una tabla llamada TablaObservar que contiene un campo llamado Version.Open().ExecuteReader(). El proveedor de SqlClient. cuando se produzca un cambio sobre la tabla Empleados (alta. Página 65 . Uso NotifiacionCambiosSQLServer.HasRows) { Cambios. Por mediación del Trigger.

podemos crear el siguiente procedimiento almacenado en SQL: CREATE PROCEDURE dbo. Programación en ADO. podemos detectar mensajes generados por el servidor de SQL con las instrucciones Raiserror y Print. 1) WITH NOWAIT SET @i = 1 + @i END END Este ejemplo provoca una demora para simular que se está realizando una operación costosa en tiempo en el servidor. Para probar un ejemplo del sistema de notificaciones. 1. En la mayoría de los casos lo recomendable sería colocar una barra de progreso que nos vaya indicando el tiempo transcurrido y que el usuario conozca el tiempo apróximado que resta para terminar la ejecución. En cada pasada realiza una notificación para que sea capturada desde nuestro programa. RAISERROR (@MSG. desde nuestra aplicación no podemos conocer el estado final del procedimiento.10. Por defecto.ProcedimientoLargo AS BEGIN SET NOCOUNT ON DECLARE @i INT SET @I = 1 WHILE @i<=10 BEGIN WAITFOR DELAY '00:00:01' --Simula una operación costosa en el SQL.6. Cada vez que cuenta tiene una demora (Waitfor Delay) para simular que está trabajando. Podemos utilizar un sistema parecido al anterior con un objeto Timer para ir moviendo la barra y ralentizando su presentación según pasa el tiempo hasta conocer el fin del procedimiento. Pero es muy costo en recursos y ademas no representa claramente el avance en tiempo de ejecución del procedimiento. Programa objetos de espera en la ejecución de operaciones Muchas veces tenemos que ejecutar en el servidor procedimientos almacenados que tienen un alto coste en tiempo de ejecución. Este ejemplo cuenta hasta 10 y para. Página 66 . Para resolver el problema contamos con el sistema de notificaciones del objeto SqlConnection. DECLARE @msg NVARCHAR(50) SET @msg = 'Progreso: ' + CONVERT(nvarchar. Al ejecutarse en el servidor. los mensajes se acumularían y serían enviados al final de la ejecución del procedimiento almacenado. @i) --Es importante colocar el WITH NOWAIT para que los mensajes --No se acumulen y se notifiquen al final. 4. que por mediación del evento InfoMessage. que permite enviar el mensaje inmediatamente se ejecute la línea. Es importante que el mensaje lanzado por Raiserror lleve la clausula With Nowait. Capítulo 4.

ConnectionString = @"Data Source=SERVIDOR. if (objReader.StoredProcedure. //Programamos el evento InforMessage para el objeto Conexión. Capítulo 4.HasRows) while (objReader.Value = 0. } } private void objConexion_InfoMessage(object sender. objConexion. El valor de Step esta definido en 10. SqlInfoMessageEventArgs e) { //Avanza la progressBar en la cantidad especificada por la //propiedad Step BarraProgreso. Página 67 .PerformStep(). if (objConexion. } En este caso hemos programado el evento click de un botón que dispara la ejecución del procedimiento almacenado y un evento InfoMessage de la conexión que se lanza cuando un mensaje Raiserror es ejecutado dentro del procedimiento almacenado.State != ConnectionState. objConexion).CommandType = CommandType.Open) objConexion.Initial Catalog=Empresa.Open().ProcedimientoLargo". En el InfoMessage simplemente llamamos al método PerformStep de la barra para que incremente su valor en la cantidad especificada. objProcedimiento. Programación en ADO.ExecuteReader().InfoMessage += new SqlInfoMessageEventHandler(objConexion_InfoMessage). private void btnEjecutar_Click(object sender. SqlCommand objProcedimiento = new SqlCommand("dbo. SqlDataReader objReader = objProcedimiento.Integrated Security=True". EventArgs e) { BarraProgreso.Read()) { //Los resultados son procesados en este bloque de código. Para capturar los mensajes implementamos el siguiente código. SqlConnection objConexion = new SqlConnection(). objConexion.

desde la aplicación. desarrollar una aplicación que permita dar de alta los empleados. Mostraremos las columnas que su CheckBox este activado. en lugar de un DataGridView. llene un DataGridView con la información del Nombre. diseñar una aplicación que permita mostrar los datos de cada unas de ellas en un DataGridView diferente. Apellidos y DNI. Ejercicio 7. Ejercicio 3. se introducirá el Id correspondiente seleccionado desde un ComboBox. Cada CheckBox es una de las columnas de la tabla. conecte con la Base de Datos de Empleados y permita modificar sus datos básicos como son. nos muestre en un DataGridView los libros comprados por cada cliente con toda la información del libro. Tomando las bases de datos de libros y teléfonos. Los ComboBox mostrarán el nombre del departamento o la categoría según corresponda. Tanto para el caso de clientes. Diseñar una aplicación que tomando la base de datos de Empresa en Access. Realizar una aplicación que manejando ADO Conectado inserte y modifique empleados desde una ficha con textbox. Ejercicio 6. que su valor correspondiente sea seleccionado desde un ComboBox. Usar ADO Desconectado. a petición del usuario. por mediación de un botón llamado CargarDatos. el SQL Server dará un error. Tomando como base el ejercicio 5. modificaciones y eliminación de categorías y departamentos. Apellido y DNI. Ejercicio 5. Ejercicio 8. Además. podremos dar altas. Nombre. Además y en otro DataGridView mostrará toda la información de los libros que componen un tema. Realizar una aplicación que permita mostrar en un DataGridView la información de la tabla empleados. Realizar una aplicación que manejando ADO Conectado. Idem que el anterior pero usando Sql Server. Se incorporará un DataGridView donde se mostrarán todos los empleados de la base de datos Empresa. Realizar una aplicación que tomando como base la base de datos Librería. Usar Access con ADO Desconectado. como para el caso de temas. Realizarlo usando Access.Ejercicios básicos de ADO Conectado y ADO Desconectado: Ejercicio 1. Ejercicio 4. pero en lugar de introducir el Departamento y la Categoría con un número. Ejercicio 2. Capítulo 4. Usar la base de datos Empresa. Página 68 . Hay que tener en cuenta que si se borra una categoría o departamento que están dados de alta en la tabla empleados. Programación en ADO. seleccionando las columnas que queremos ver desde un panel con CheckBox. Usar la base de datos Empresa.