UNIVERSIDAD DON BOSCO FACULTAD DE ESTUDIOS TECNOLÓGICOS ESCUELA DE COMPUTACIÓN CICLO: 02/2013 GUÍA DE LABORATORIO #10 Nombre de la Práctica: ADO .NET y conexiones a Base de Datos. Parte II Lugar de ejecución: Centro de computo Tiempo estimado: 2 horas con 30 minutos MATERIA: Lenguaje de Programación I I. OBJETIVOS Qué el estudiante: Presentar conjuntos de datos específicos de una BDD en una aplicación. Filtrar datos presentados al usuario por medio de la transferencia de parámetros a una consulta SQL de selección. II. INTRODUCCIÓN TEÓRICA. ADO.NET ADO.NET es la tecnología de acceso a datos utilizada por Visual Studio .NET y por el resto de aplicaciones del .NET Framework. Forma parte integral de .NET Framework, y proporciona acceso a datos relacionales, datos XML y datos de aplicaciones. ADO.NET utiliza un modelo de acceso pensado para entornos de datos desconectados. Esto quiere decir que la aplicación se conecta al origen de datos, hace lo que debe de hacer, por ejemplo seleccionar registros, los carga en memoria y se desconecta del origen de datos. La arquitectura ADO.NET permite crear componentes que administran eficientemente datos procedentes de múltiples orígenes, y también proporciona las herramientas necesarias para solicitar, actualizar y reconciliar datos entre grupos de aplicaciones. Componentes de ADO.NET Usted necesita desarrollar 3 pasos mínimos para acceder a sus datos almacenados: 1. Acceder al Origen de Datos y mostrar los datos en el formulario o Web 2. Manipular los Datos 3. Retornar los datos modificados para actualizar la base de datos ADO.NET es un conjunto de clases que usted utiliza para acceder y manipular orígenes de datos como por ejemplo, una base de datos en SQL Server o una planilla en Excel o una base de datos Access, etc. Utiliza XML como el formato para transmitir datos desde y hacia su base de datos y su aplicación Web. El modelo de objetos ADO.NET provee una estructura de acceso a distintos orígenes de datos. Esta estructura de acceso tiene 2 componentes principales: A) Un Proveedor de Datos .NET b) Un objeto de la clase DataSet. Facultad de Estudios Tecnológicos 1 EL PROVEEDOR DE DATOS .NET Permite el enlace entre el Origen de Datos y un objeto DataSet. Un proveedor de datos de .NET Framework es el que se conecta a una base de datos, ejecuta comandos y recuperara resultados. Esos resultados se procesan directamente o se colocan en un DataSet de ADO.NET con el fin de exponerlos al usuario para un propósito específico, junto con datos de varios orígenes, o de utilizarlos de forma remota entre niveles. Para comenzar, usted debe determinar un origen de datos y luego seleccionar el proveedor de .NET adecuado a) Un Origen de Datos es el deposito de datos al cual necesita enlazar a su aplicación .NET, por ejemplo: una Base de datos (Ejemplo: Access, SQL Server, Oracle) o también datos personalizados en archivos XML u otros formatos. b) Espacios de nombres (Namespace) para manejo de datos en el .NET Framework: Para tener acceso a las diversas clases de acceso a datos de un proveedor específico, debe importar a sus formularios el espacio de nombres System.Data el cual contiene diversos espacios de nombres con clases especializadas de acuerdo al proveedor de datos que desee acceder por medio de su aplicación Entre los espacios de nombres de .NET Framework relativos a datos y XML incluidos en el namespace Data tenemos: System.Data.OleDb Clases que componen el proveedor de datos de .NET Framework para orígenes de datos compatibles con OLE DB. Estas clases permiten conectarse a un origen de datos OLE DB, ejecutar comandos en el origen y leer los resultados. System.Data.ODBC Clases para conectarse a orígenes de datos compatibles con ODBC. System.Data.Xml Clases que proporcionan funcionalidad basada en estándares para procesar código XML. System.Data.SqlClient Clases que conforman el proveedor de datos de .NET Framework para SQL Server, que permite conectarse a un origen de datos SQL Server 7.0, ejecutar comandos y leer los resultados. El espacio de nombres System.Data.SqlClient es similar al espacio de nombres System.Data.OleDb, pero optimizado para el acceso a SQL Server 7.0 y versiones posteriores. System.Data.SqlTypes Proporciona clases para tipos de datos nativos de SQL Server. Estas clases ofrecen una alternativa más segura y más rápida a otros tipos de datos. System.Data.OracleClient Clases que componen el proveedor de datos de .NET Framework para Oracle. Estas clases permiten el acceso a orígenes de datos Oracle en el espacio administrado. Clases de objetos provistos por los proveedores de datos .NET Existen 5 clases de objetos fundamentales del modelo de acceso a datos proporcionados por cada proveedor de datos. Los objetos generales Connection, DataAdapter, DataReader, Command y Parameter son integrados dentro del .NET Framework. Cada proveedor de la tabla anterior define las clases que definen a estos objetos. Por ejemplo, en la tabla siguiente se muestra una descripción de estas clases generales y los nombres de clases de objetos para el proveedor de OLEDB y de SQL Server: Clase para origen SQL Clase para un origen Objeto Descripción Server OLEDB Connection Establece una conexión a un SqlConnection OleDBConnection origen de datos determinado. Facultad de Estudios Tecnológicos 2 DataReader DataAdapter Command Parameter Lee una secuencia de datos de sólo avance y sólo lectura desde un origen de datos Llena un DataSet y realiza las actualizaciones necesarias en el origen de datos Ejecuta un comando SQL en un origen de datos Cuando ejecuta un comando el cual requiere que definan argumentos, los objetos de la clase Parameter permiten definir el nombre y valor de cada uno de estos parámetros que se envían desde la aplicación por medio de un objeto Command SqlDataReader OleDBDataReader SqlDataAdapter OleDBDataAdapter SqlCommand OleDBCommand SqlParameter OleDBParameter Configuración de un objeto Command Cuando ha establecido una conexión, muchas veces será necesario ejecutar instrucciones SQL para realizar actualizaciones a los registros de las tablas o también ejecutar funciones almacenadas en la BDD. Los objetos de la clase Command permiten definir la funcionalidad de una instrucción SQL dentro de ADO.NET, por medio de la asignación de sus propiedades, las cuales son: Propiedades del objeto Command Propiedad Connection CommandText CommandType Descripción Valores aceptados por la propiedad Nombre de Objeto de una conexión activa Almacena el texto del comando a ejecutar por el origen Este se redacta en formato SQL Indica como debe interpretarse el texto de la instrucción SQL. Variable objeto de la clase Connection la cual este actualmente abierta String con la sentencia SQL que desea que ejecute la BDD enlaza por la conexión activa Text: valor predeterminado. Se usa solo para instrucciones que administren registros, por ejemplo: select, insert y delete StoredProcedure: para instrucciones que activan/ejecutan funciones almacenadas en el origen de datos. TablaDirect: Equivale a ejecutar la consulta SQL SELECT * FROM nombretabla, y nombretabla es el nombre de una tabla especificada en CommandText Usted puede asignar las propiedades CommandText y CommandType, pero el comando solo se ejecutara cuando establezca un objeto Connection a la primera propiedad, el cual también debe esta abierto . OBJETOS PARAMETER: Agregando parámetros a un objeto Command La mayoría de procedimientos almacenados en un origen de datos y algunas consultas SQL poseen uno o mas parámetros. Estos parámetros son útiles en los procedimientos almacenados ya que funcionan igual que en una función de VB. Facultad de Estudios Tecnológicos 3 Ejemplos de instrucciones que necesitan argumentos (los cuales se muestran resaltados): EJEMPLO: Instrucción SQL y significado select * from Mitablita where TotalVentas>20 Es una instrucción de consulta que permite seleccionar de la tabla Mitablita solo los registros que cumplan que el valor del campo TotalVentas sea mayor que 20. El argumento en este caso es una condición que relaciona el nombre de un campo y su valor(20). update Mitablita SET Nombre=‟Sara‟ where IdCliente=12 Similar a la instrucción anterior, pero ahora solo actualizara el valor del campo Nombre en todos los registros que tengan en su campo IdCliente el valor (12). Suponga que tiene una BDD almacenada en un servidor SQL Server. Dentro de la BDD define a un procedimiento llamado miProcedimiento con estas instrucciones: CREATE PRECEDURE miProcedimiento @miDato char(11) AS SELECT * FROM otraTabla T where Nombre=@miDato Observe que el procedure tiene un argumento llamado @miDato el cual es de tipo char de 11 caracteres y se utiliza dentro de la definición del mismo para evaluar una condición dentro de una consulta Select Retornando a .NET, suponga que quiere ejecutar una instrucción SQL que permita ejecutar este procedure almacenado en el servidor desde una conexión SqlClient. Si crea un objeto Command, le puede asignar el valor siguiente a su propiedad CommandText: miProcedimiento 'Norma' Con esta instrucción se quiere ejecutar al procedimiento almacenado miProcedimiento, enviando un argumento con el valor de „Norma‟ Para que un objeto Command pueda manejar los parámetros (con su respectivo valor) en una instrucción SQL que los necesite para ejecutarse, este solo necesita el nombre del procedimiento almacenado a ejecutar y cada parámetro que requiera, porque el cuerpo de instrucciones las ejecuta la BDD. Para estos casos, un objeto Command posee una colección de Objetos Parameter. Y cada objeto Parameter consta de las siguientes propiedades mínimas con las que se le definen a cada parámetro que necesite una instrucción SQL: Propiedad Descripción Name Type Length Direction El nombre del parámetro del procedimiento El tipo de datos del parámetro tamaño del tipo de dato El uso del parámetro, si será de envío a la BDD (Input) o retornado de la BDD (Output) Valor a usar en la consulta generado desde VB.NET Value Ejemplo: Observe el ultimo ejemplo de los objetos Parameter @miDato String 11 Input Norma Cada parámetro se agrega a la colección Parameters de un objeto Command por medio del metodo Add. Facultad de Estudios Tecnológicos 4 Ejemplo: de nuevo observe el ejemplo del procedimiento almacenado (miProcedimiento) y analice como se define un comando para ejecutar el procedimiento almacenado, luego se crea un parámetro y asigna el valor “Norma”, y por ultimo como incluye este Parameter a un comando con el uso del metodo Add: 'Cree un enlace hacia la BDD Northwind dentro del servidor SQL local, y con usuario “sa” Dim Conex as New SqlConnection(“Data Source=(local); Initial Catalog=Northwind;User id=sa”) Dim cmd As New SQLCommand Dim pm As SqlParameter Conex.Open() 'Activo la conexion 'Configuro el comando para llamar al procedimiento almacenado miProcedimiento cmd.CommandType=CommandType.StoredProcedure cmd.CommandText= “miProcedimiento” cmd.Connection= Conex „Enlazo a un objeto Connection que esta abierto 'Creo y configuro un parametro que necesita proc miProcedimiento pm =new SqlParameter With pm .Name=”@miDato” .Type=SqlDbType.Char .Length=11 .Direction=ParameterDirection.Input 'Valor que tomara dicho parámetro para que el proc miProcedimiento funcione .Value=”Norma” End With 'Agrego el parámetro pm configurado anterior al objeto cmd con el metodo add cmd.Parameters.Add(pm) Es de aclarar que muchas de las propiedades de ADO.NET tienen la habilidad de interpretar cada parámetro con solo saber las propiedades Name y Value. Asi que el With usado para objeto pm anterior puede ser simplificado a una de estas formas: FORMA 1 FORMA 3 With pm .Name=”@miDato” Tambien puede crear un objeto Parameter solo al momento de llamar al .Value=”Norma” método Add de la colección Parameters. Aquí le declara las 2 End With propiedades mínimas por medio de su constructor así: cmd.Parameters.Add(pm) „Agrego un parámetro al Command cmd cmd.Parameters.Add(New SqlParameter(“@miDato”,”Norma”)) FORMA 2 pm.Name=”@miDato” pm.Value=”Norma” Ejemplo: Definiendo un Objeto OleDBCommand con dos parámetros. Observe con mucho cuidado los cambios con el ejemplo anterior al momento de escribir el comando SQL dentro del Command de OLEDB Dim conexOle As New OleDBConnection (“Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\miBDD.mdb”) Facultad de Estudios Tecnológicos 5 ConexOle.Open() 'cree un objeto Command con dos parámetros, cuyos valores se presentan como ( ? ) Dim cmdOle As New OleDb.oledbcommand(“select * from Tabla where Ciudad = ? and Region = ?”) 'agregue un objeto Parameter para sustituir al primer parámetro (@ciudad) Dim paramOle As OleDb.OleDbParameter=cmdOle.Parameters.Add(“@Ciudad”, OleDb.OleDbType.Varchar, 30) paramOle.value=”San Luis” „Valor asignado a param desde aplicac (no desde la BDD) 'agregue otro objeto parámetro para sustituir el Segundo parametro (@region) paramOle= cmdOle.Parameters.Add(“@region”,OleDb.OleDbType.Varchar, 2) paramOle.value=”Oriente” 'Ejecute el command y almacene datos devueltos en un OleDataReader Dim oleDataReader As OleDb.OleDbDataReader= cmdOLe.ExecuteReader (CommandBehavior.CloseConnection ) 'Muestra el resultado de la primera columna de cada una de filas en secuencia While oleDataReader.Read Msgbox(oleDataReader.Getvalue(0).ToString()) End while 'Cierra el lector de datos y la conexión oleDataReader.Close() ConexOle.Close() Elegir un método para ejecutar el Command Después de haber configurado las propiedades de un objeto Command (incluyendo los parámetros cuando los necesite), es posible ejecutarlo llamando a uno de sus métodos de ejecución que se listan a continuación: Metodos para Ejecutar una instrucción SQL dentro del Objeto Command ExecuteNonQuery : ejecuta una instrucción SQL que no devuelve registros, entonces puede ser una instrucción Delete, Update o Insert, También se usa si el procedimiento almacenado solo devuelve salidas a través de parámetros. ExecuteReader : Ejecuta instrucción y devuelve un objeto SqlDataReader que contiene los registros resultantes de la consulta SQL del Command ExecuteScalar : se usa cuando hay que devolver un solo valor (columna) de datos de una instrucción SQL Select ExecuteXMLReader : solo es permitido para un Command del proveedor SQL Server (Clase SQLCommand). Es parecido a ExecuteReader, pero devuelve un XMLReader Existen diversos métodos de ejecución para así optimizar los tipos de instrucciones SQL disponibles, y usted debe seleccionar el método que mas se ajuste a sus necesidades. Ejemplo: Suponga que desea borrar un conjunto de registros de una tabla llamada Empleados de una BDD por medio de la instrucción SQL DELETE. El segmento que realiza esta tarea es la siguiente: Dim TextoSql As String Facultad de Estudios Tecnológicos 6 Dim TotFilasBorradas As Integer Dim valor As String = “Juan” Dim cmd as New SqlCommand( ) TextSql=”Delete from Empleados where MiCampo= '“+valor+”'” 'Configuro el objeto command With cmd .Connection= ObjetoConex „Asumo que este objeto es un Connection que esta abierto .CommandText=TextSql End With 'Ejecuto la instrucción Delete del objeto Command TotFilasBorradas = cmd.ExecuteNonQuery() 'Muestro total de filas que fueron borradas en la BDD Msgbox( TotFilasBorradas.ToString ) Usar los lectores de datos DataReader y DataSet Cuando ejecuta una consulta SELECT o un procedimiento almacenado que devuelve registros, es necesario utilizar un método de ejecución que le permita acceder a estos registros. Un objeto Command puede ejecutar instrucciones SQL que devuelvan conjuntos de registros por medio de los métodos de ejecución ExecuteReader. .El método ExecuteReader devuelve un objeto DataReader, pero este no puede funcionar de un modo desconectado porque esta clase esta hecha para extraer los registros de una BDD lo mas rápido posible para procesarlos secuencialmente (solo en una dirección), por lo que la capacidad de desplazamiento esta limitada al movimiento hacia delante de los registros obtenidos. Un DataReader consta de los métodos siguientes para leer valores de cada registro y/o campo: Metodo de DataReader Read Item(Indice o nombre) GetName Metodos varios Get FieldCount IsDBNull Descripción Método que coloca un señalizador(posición del registro actual) en el próximo registro a leer por el DataReader Propiedad que devuelve el valor de un campo especifico de los datos ya sea por un entero(Índice) o sino un string del nombre de un campo Función que devuelve el nombre de una columna/campo de los datos Son un conjunto de funciones que inician con las letras Get. Estas devuelven valor de un campo (con un índice) en un tipo de dato específico (como String, Entero, Decimal, etc). Ejemplos de estas funciones: GetString, GetBoolean, GetDouble y otras mas Función que devuelve numero de columnas/campos de los datos recibidos Función que permite saber si hay un valor Null en una columna de los datos Facultad de Estudios Tecnológicos 7 OBJETO DATAADAPTER Los objetos de la clase DataAdapter proporcionan los medios para que los objetos del DataSet puedan interactuar con una BDD. Un objeto DataAdapter proporciona el esquema de asociación completo de la BDD al formato XML según el objeto DataSet; tambien asocia el XML devuelto por un DataSet a los objetos Insert, Update y Delete, y establece todos los parámetros en consecuencia. Un DataAdapter permite albergar cuatro objetos Command de ADO.NET. Cada uno de estos comando contiene las instrucciones/parámetros SQL necesarios para realizar una de las 4 acciones SQL principales sobre una BDD: Select, Insert, Update y Delete. Entonces un objeto DataAdapter presenta estos 4 command como propiedades llamadas: SelectCommand, InsertCommand, UpdateCommand y DeleteCommand. El programador puede configurar previamente estos cuatro objetos Command para obtener control absoluto sobre un conjunto concreto de interacciones con una BDD. OBJETO DATASET Es el segundo componente fundamental de la arquitectura de ADO.NET. Después de que usted establece una conexión con una Base de Datos por medio de un proveedor, puede acceder entonces a sus datos por medio de objetos de la clase DataSet. Un DataSet guarda la información recibida desde una conexión y trabaja en un entorno desconectado, esto significa que los datos en un DataSet pueden ser manipulados sin necesidad que el formulario mantenga una conexión “permanente” con el origen de datos. La conexión solo se reestablece cuando usted necesita actualizar cambios. Este puede contener datos de múltiples tablas, sus campos y además las relacionesrestricciones que las asocian entre si. Prácticamente un DataSet viene a ser una caché de memoria interna de datos recuperados de un origen de datos o algo así como una BDD portátil. Ahora aprenderá como colocar registros de una BDD en un objeto DataSet, modificarlos y por ultimo enviar los cambios hechos en los datos de un DataSet a la BDD. Presentacion de DataAdapter Para poder tranferir registros a y desde un DataSet, es necesario utilizar un objeto de la clase DataAdapter. Un DataAdapter es un adaptador de datos que permite establecer un puente entre un origen de datos y un objeto DataSet. Un DataAdapter difiere de las clases Command explicadas antes porque un Command se comporta como una “funcion” que devuelve registros. En cambio un DataAdapter posee varias propiedades que representan objetos de Command individuales, los cuales son: SelectCommand, UpdateCommand, InsertCommand y DeleteCommand. Un DataAdapter transfiere los registros de una BDD utilizando los comandos mencionados. En general, la preocupación principal de un DataAdapter consiste en saber como se asignan los datos a y desde una BDD origen. Recuperando registros hacia un DATASET Un control DataAdapter consta de una serie de métodos con los cuales puede recuperar/enviar información desde/hacia un Origen de datos especifico. Entre los métodos más importantes tenemos: Facultad de Estudios Tecnológicos 8 Metodo Fill: permite recuperar registros de una BDD y así rellenar un DataSet con los registros resultantes de una consulta a una BDD o sino de una fuente XML. El método Fill tiene varias sobrecargas, de las cuales la más usada solicita el objeto DataSet que guarde los datos recuperados y un String que indique el nombre del DataTable interior que tendrá los datos. Este último por lo general es el nombre de la tabla Metodo FillSchema: se usa para configurar un objeto DataTable situado dentro de un objeto DataSet con el esquema de la BDD e información restringida antes de completar el objeto DataTable mediante el DaraAdapter. Por ejemplo, el objeto DataTable debe conocer información restringida asignada por la BDD como la clave principal o campos autonuméricos de una tabla, para poder actualizar o eliminar información de forma adecuada. Este método FillSchema se basa en la instrucción SQL indicada en el objeto SelectCommand para obtener la información de esquema específica de la BDD. Como acceder a los valores de los campos de una tabla Acceder a los registros individuales de un DataSet rellenado es distinto a acceder ellos por medio de un DataReader, ya que no existe un registro activo ni método de movimiento asociado. En su lugar, se utilizan colecciones de objetos hijos dentro de un DataSet que permiten organizar las tablas, filas y los valores de cada campo de los resultados de datos almacenado en el DataSet. Las clases de estos objetos incluidos dentro de un DataSet que permiten manejar los registros de una o más tablas están organizados en una jerarquía dentro de un objeto DataSet. Las clases y su jerarquía son las siguientes: Jerarquia Clase Descripción de la clase 1 Tables Acceso a una de las tablas dentro de los resultados de un DataSet 2 Column Define las caracteristicas de cada campo obtenido de la consulta SQL aplicada. Estas características pueden ser: Tipo de dato, Si puede o no tener valor nulo(vacio), si es autonumérico (devolviendo el valor inicial del conteo, incremento y ultimo valor utilizado en los registros) 3 Rows Contiene el conjunto de registros individuales(Filas) que le pertenecen a una tabla especifica 3 Item Almacenan los valores individuales de los campos del registro seleccionado Todas las clases anteriores se manejan como “arreglos de objetos” ya que debe utilizarse un índice entero para saber a cual objeto de la colección se refiere al programarlo. Ejemplo: Si por ejemplo se tiene un DataSet llamado DStabla. Con la instrucción siguiente se mostraría el valor del quinto campo del segundo registro(fila) de la primera tabla almacenada en el DataSet: Msgbox (DStabla.Tables(0).Rows(1).Item(4).ToString) Observe que el conteo entero para referirse a un objeto en particular comienza con 0 (al igual que como se maneja los índices de los arreglos en lenguaje C, Java y otros). Facultad de Estudios Tecnológicos 9 Ejemplo: También podría usar identificadores con nombres (en lugar de enteros) para facilitar el desplazamiento, así por ejemplo: With DStabla.Tables(0) For i=0 To .Rows.Count-1 MsgBox(.Rows(i).Item(“Campo2”)) Next End With El código anterior imprime en pantalla el valor del campo llamado Campo2 de cada una de las filas de la primer tabla dentro del DataSet DSTabla. Como cargar múltiples tablas desde una conexión Dentro de un DataSet puede colocar los registros de dos o más tablas e incluso establecer las relaciones (uno a uno, uno a varios) entre ellas. Puede hacer esto de dos formas diferentes: 1. llamar al método Fill de un DataAdapter sobre múltiples objetos DataAdapter utilizando el mismo DataSet como argumento de Fill. 2. Ejecutar un procedimiento almacenado con más de una instrucción SELECT, En este caso solo bastara un solo objeto DataAdapter. Como agregar restricciones y relaciones Además de almacenar tablas, un objeto DataSet tiene la capacidad de almacenar relaciones y restricciones como lo hace la BDD. Dado que es posible modificar los datos de un DataSet mientras se esta desconectado de la BDD, el administrador de la BDD no estará presente para exigir las restricciones como por ejemplo: los campos únicos y las llaves principales. Ejemplo: El código siguiente muestra un nuevo objeto, el objeto DataColumn, que representa un campo de una tabla de datos. Es posible establecer la propiedad Primary Key de cada tabla dentro de un DataSet a una matriz de estas columnas, con el fin de definir la clave principal. La columna SSN es la clave principal de la tabla Person. Las columnas SSN y Dept forman conjuntamente la clave principal de la tabla Emp loyee. SSN también es una clave externa de la tabla Employee, por lo que, con el fin de mantener la integridad de la BDD, habría que eliminar un registro de la tabla Employee si la persona correspondiente fuera eliminada de la tabla Person. Creando un objeto ForeignKeyConstraint, podemos garantizar que esto se realiza de forma automática. 'configura los objetos de columna para un acceso mas sencillo Dim colSSNP, colSSNE as DataColumn colSSNP=dsMain.Table(“Person”).Columns(“SSN”) colSSNE=dsMain.Table(“Employee”).Columns(“SSN”) „Crea las claves principales Dim arPersKey(1) as DataColumn Dim arEmplKey(2) as DataColumn arPersKey(0)=colSSNP arEmplKey(0)=colSSNE arEmplKey(1)=dsMain.Tables(“Employee”).Columns(“Dept”) Facultad de Estudios Tecnológicos 10 dsMain.Tables(“Person”).PrimaryKey=arPersKey dsMain.Tables(“Empleyee”).PrimaryKey=arEmplKey 'Crea la clave externa para eliminación en cascada Dim fkSSN As ForeignKeyConstraint fkSSN=new ForeignKeyConstraint(“SSNForKey”,colSSNP,colSSNE) fkSSN.DeleteRule=Rule.Cascade dsMain.Tables(“Empleyee”).Constraints.Add(fkSSN) Si muestra estos datos en 2 dataGrid (uno por cada DataSet) vera que si elimina un registro de la tabla Person, desaparecerá el correspondiente registro o registros de la tabla Employee, debido a la restricción de la llave primaria. Como mostrar el contenido de un DataSet El concepto de enlace de datos implica asociar un formulario con un campo o una tabla de datos. El control maneja el desplazamiento, las actualizaciones y las eliminaciones, por lo que no será necesario escribir código para actualizar los registros del DataSet que están enlazados a el. En el entorno de datos desconectados que utiliza ADO.NET los controles enlazados a datos no se comunican directamente con la BDD, sino que lo hacen con los datos de un DataSet local. Ejemplos de enlace de un DataGrid: Ejemplo 1: Grid1.DataSource= nombreDataSet 'Especifica nombre de una de las tablas almacenada en DataSet anterior. Grid1.DataMember=”NombreTabla1” Grid1.CaptionText =”NombreTabla1” Ejemplo 2: 'borra el enlace activo Grid1.DataMember=”” Grid1.DataSource=Nothing Como filtrar la visualizacion de las filas En el grid anterior, se ha asignado el objeto DataTable a la propiedad DataMember del Grid, y muestra cada registro de la tabla con todas las opciones de edición posibles. Sin embargo, a veces solo será necesario mostrar ciertas filas o prohibir a los usuarios que modifiquen su contenido. Un filtro permite determinar que registros de una tabla van a ser visibles y que restricciones de acceso asignarle. Es similar a una clausula WHERE de SQL. Ejemplo: With DataSet1.Tables(“Person”) .DefaultView.RowFilter=”NombreCampo Like „ ”+”Norma”+” %‟ ” .DefaultView.AllowDelete =False .DefaultView.AllowEdit =False Facultad de Estudios Tecnológicos 11 .DefaultView.AllowNew =False Grid1.DataSource= .DefaultViuw En with Grid1.CaptionText= “Filtrado en el ultimo nombre” Como verificar los registros modificados Un objeto DataTable contiene múltiples objetos DataRow, cada uno de los cuales representa un registro de la tabla. Puede modificar el contenido del DataSet o bien cambiar los valores de un objeto DataRow en especial, o bien utilizar un Grid enlazado. Una característica interesante de la clase DataSet es la capacidad de saber que filas han sido modificadas. Esto es importante, ya que el DataSet se encuentra desconectado de su BDD, así que deberá saber si ha habido adición, eliminación o actualización de filas, para que los cambios puedan ser enviados a una BDD. Por ejemplo si una tabla tiene 1000 registros y usuario solo modifica 12 filas, será mejor que solo se envié el listado de solamente estas filas modificadas y así no saturar a la BDD con actualizaciones innecesarias. Para manipular los cambios de un DataSet, este consta de los siguientes métodos y propiedades: RowState : determina los cambios realizados en una fila GetChanges : devuelve un nuevo objeto DataSet que solo contiene las filas modificadas AcceptChanges : coloca todos los cambios en el DataSet activo, restableciendo la propiedad RowStare RejectChanges: deshace los cambios en el DataSet y lo retorna al estado de la versión original, o la versión que hacia desde la ultima llamada a AcceptChanges. Como actualizar los registros en una BDD El paso final de la interacción entre los objetos DataAdapter y DataSet es el método Update del primer objeto mencionado. Este método acepta el objeto DataTable como parámetro y se repite a través de cada objeto DataRow del objeto DataTable. El metodo DataTable establece la asociación de cada fila del objeto DataTable con el método Insert, Update o Delete adecuado en función del estado de la fila. Esencialmente, el método Update se encarga de procesar en lotes la actualización de los datos en una sola invocación. Puede trabajar sobre un conjunto de datos sin conexión dentro de un DataSet y propagar todos sus cambios a la BDD mediante objetos Command preconfigurados con una sola invocación al metodo Update del objeto DataAdapter apropiado. Ejemplo 1: Configuración de un objeto DataAdapter mediante la asociación manual de objetos Command 'Cree objeto connection Dim oconnection as new sqlclient.sqlconnection(“CADENA CONEXION”) Oconnection.open() 'cree un adaptador de datos vacio Dim oDataAdapter as new sqlclient.sqldatadapter() 'cree una instruccion Select Facultad de Estudios Tecnológicos 12 Dim oselectcommand as new sqlclient.sqlcommand(“select ClienteID, nombreEmpresa, NombreContacto from Clientes”, oconnection) 'cree una instrucción Insert y añada los parámetros adecuados Dim oInsertCommand as new SqlClient.sqlcommand(“insert into Clientes( NombreEmpresa, NombreDeContacto) values (@NombreEmpresa,@NombreDeContacto)”,oconnection) oInsertcommand.parameters.add(new sqlclient.sqlParameters(“@@NombreEmpresa”,system.data.sqldbtype.NVarChar, 20, System.Data.ParameterDirection.Input, True, Ctype(0,Byte), Ctype(0,Byte), ”NombreEmpresa”, System.DataRowVersion.Current, Nothing)) oInsertcommand.parameters.add(new sqlclient.sqlParameters(“@NombreDeContacto”,system.data.sqldbtype.NVarChar, 20, System.Data.ParameterDirection.Input, True, Ctype(0,Byte), Ctype(0,Byte), ”NombreDeContacto”, System.DataRowVersion.Current,Nothing)) 'cree una instruccion Update y añada los parametros adecuados Dim oupdatecommand as new sqlclient.sqlcommand( “update clientes set NombreEmpresa= @NombreEmpresa, NombreDeContacto=@nombreDeContacto where ClienteID= @ClienteID”, oconnection) Oupdatecommand.parameters.add( new sqlclient.sqlparameter ( “@NombreDeContacto”, system.data.sqltype.nvarchar, 20, system.data.parameterdirection.input, true, ctype(0,byte), ctype(0,byte), ”NombreDeContacto”, system.data.datarowversion.current, nothing) ) Oupdatecommand.parameters.Add( New sqlcliente.sqlparameters( “@ClientID”, system.data.sqldbtype.int, 5,system.data.parametersdirection.input,true,ctype(0,byte),ctype(0,byte), ”ClienteID”, system.data.datarowversion.Current, Nothing) ) 'Creo el comando delete con el parámetro (ClienteID) unicamente Dim odeletecommand as new sqlclient.sqlcommand( “delete from Clentes where Cliente= @ClienteID”, oconnection ) Odeletecommand.parameters.add( new sqlclient.sqlparameter ( “@ClienteID”, system.data.sqldbtype.int. 5, system.data.parameterdirection.input, true. Ctype(0,byte), ctype(0,byte), “ClienteID”, system.data.datarowversion.current, nothing ) ) 'establece las referencias apropiadas al objeto sobre DataAdapter With oDataAdapter .selecctCommand= oSelectCommand .insertCommand= oInsertCommand .UpdateCommand= oUpdateCommand .DeleteCommand= oDeleteCommand End With „Cree un espacio para el conjunto de datos vacio Dim oDataSet as New DataSet() 'Use el Adapter para crear un relleno de la nueva DataTable denominado Clientes oDataAdapter.Fill ( oDataSet, “Clientes”) dim snuevonombre as string=”Kevin” oDataSet.Tables(0).Rows(0).Item(“NombreDeContacto”)= snuevonombre oDataSet.Update(oDataSet) oConnection.Close() Facultad de Estudios Tecnológicos 13 III. REQUERIMIENTOS O MATERIAL Y EQUIPO N° 1 2 3 Cantidad 1 1 1 Descripción PC con Windows y acceso a Internet Guía de Laboratorio #10 de LPI Memoria USB IV. PROCEDIMIENTO Antes de iniciar esta práctica tenga en cuenta lo siguiente: a) Debe crear una carpeta en Mis Documentos con el nombre de “Práctica10LP1” en la cual va a guardar todos los archivos del procedimiento y del análisis de resultados. b) Tome en consideración que la extensión del archivo de la BDD de Access es .mdb solo para Access 2003 o versiones anteriores. En esta práctica utilizará Access 2007 por lo cual será .accdb Archivo: TazumalSA.accdb 1. Cree una nueva base de datos dentro de su carpeta de trabajo llamada TazumalSA.accdb, la cual contenga las siguientes tablas y relaciones entre ellas: 2. Tome en cuenta las restricciones (dominio de valores) de los campos siguientes: Tabla Proveedor Categoria Producto Dominio de campos de la tabla IdProv: autonumerico y llave primaria El resto de campos tienen 20 caracteres cada uno, solo el nombre del proveedor y contacto son obligatorios. IdCatego: campo llave primaria de 2 caracteres El resto de campos son de 30 caracteres cada uno, y exija valor en ellos(no permitir nulos) IdProd: autonumerico y llave primaria NomProd: texto de 25 caracteres y no nulo IdProv: Entero largo y no nulo IdCatego: texto de 2 caracteres y no nulo PrecioUnidad: numero Flotante Doble UnidadesEnExistencia: Entero Facultad de Estudios Tecnológicos 14 JerarquiaEmp Empleado 3. IdJerar: autonumerico y llave primaria NomJerar y FuncionesJerar: texto de 25 y 40 caracteres respectivamente, no nulos. IdEmp: autonumerico y llave primaria Ape1Emp, Ape2Emp, NomsEmp: texto de 10 caracteres no nulos IdJerar: Numero entero largo no nulo DirecEmp y TelCasaEmp: texto de 50 y 15 caracteres respectivamente, permitir nulos Ingrese los datos siguientes a cada una de las tablas de la manera apropiada: JerarquiaEmp IdJerar NomJerar 1 Vicepresidente comercial 2 Representante de ventas 3 Gerente de ventas 4 Seguridad FuncionesJerar Dueños del negocio Interactuar con clientes Coordinar representantes de ventas Proteger local de ventas Empleado IdEmp 1 2 3 4 Ape1Emp Castillo Pineda Giron Perez 5 Garcia Ape2Emp Letona Zelaya Moreno A Tobar NomsEmp IdJerar DirecEmp Bernando 1 Soyapango Paty 2 El paraiso San Salvador Enrique 3 Apopa Alicia 3 Soyapango Rosa 3 Ilopango 6 Garcia 7 Dimas Garcia Sergio 4 Las Margaritas Moreno Juan 4 Mejicanos TelCasaEmp 122222 222888888 556-999 3244444 2545555 Producto IdProd NomProd IdProv IdCatego PrecioUnidad UnidadesEnExistencia 1 Barrilito 1 a1 1,34 31 2 Pilsener 1 a1 2 100 3 Sardina PICANADA 2 a3 0,67 120 Proveedor IdProv 1 2 3 4 NombreProv La Constancia La Isla San Francisco Pizza Hot ContactoProv Francisco Merino Popeye marino Elizabeth Garcia Rosa Garcia DirecProv La calle alegre Puerto Libertad Santa Tecla Colonia Escalon Telefono 222-4444 766-3333 290-1111 230-7777 Categoria IdCatego a1 a2 a3 a4 NomCatego Bebidas Lacteos Pescados Pastas DescripCatego te y cervezas Quesos y Crema Sardinas y mariscos Mezclas de harina Facultad de Estudios Tecnológicos 16 4. Almacene los datos de las tablas y cierre la BDD APLICACIÓN 1(Formulario1): Obtener registros de SELECT de una tabla o sino de tablas relacionadas 5. Incluya en su proyecto a un archivo de Modulo de variables y digite en el las líneas siguientes: Dim sAppPath As String = Application.StartupPath.ToString Dim sBaseDatos As String = sAppPath & "\TazumalSA.accdb" Public CadConex As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sBaseDatos '& ";Persist Security Info=False" 6. Diseñe el form siguiente y luego ajuste las propiedades de los controles descritos en la tabla DataGridView1 Cuadro de propiedades Control Propiedad Form1 Name Button1 Text GroupBox1 Text 7. Valor Formulario1 Ver Resultados Selección de Consulta SQL Control DataGridView1 RadioButton1 RadioButton2 Propiedad Name Text Text RadioButton3 Text Valor Grid1 SELECT INNER JOIN LEFT JOIN Digite los códigos siguientes de acuerdo a la ubicación indicada A nivel del modulo de clase (antes de la declaración de clase), importe el espacio de nombres del proveedor OLEDB a utilizar: Imports System.Data.OleDb Dentro del modulo de la clase Formulario1 'Demostracion de diferentes consultas SELECT SQL Dim CadSQL As String 'texto del comando SQL Facultad de Estudios Tecnológicos 17 'Usa objetos de clases de proveedor OLEDB Dim Conex As OleDbConnection Dim DAempleado As OleDbDataAdapter En la subrutina de evento Load del Formulario1 'Define conexion a una BDD de Access Conex = New OleDbConnection(CadConex) Conex.Open() 'Activa la conexion 'Diferentes tipos de consultas Select entre una o 2 tablas(relacionadas) 'Primera opcion CadSQL = "select NomProd,PrecioUnidad,(PrecioUnidad*8.75) as Colones, UnidadesEnExistencia as Existencia from Producto" En cada subrutina de evento CheckedChanged de cada radiobutton escriba una de estas líneas: Radiobutton1: CadSQL = "select NomProd,PrecioUnidad,(PrecioUnidad*8.75) as Colones,UnidadesEnExistencia as Existencia from Producto" Radiobutton2: CadSQL = "select a.IdProv,a.NombreProv,b.NomProd from Proveedor a inner join Producto b on a.IdProv=b.IdProv" Radiobutton3: CadSQL = "select a.IdProv,a.NombreProv,b.NomProd from Proveedor a left join Producto b on a.IdProv=b.IdProv" En subrutina de evento Clic de Button1 'Muestra resultados de consulta seleccionada Dim c, f, H As Integer 'Contadores de columnas, filas y usosVarios 'Objeto DataSet: define y se instancia "vacio" (sin datos) Dim DSemp As New DataSet 'Crea un DataAdapter que copie registros segun la consulta SQL DAempleado = New OleDbDataAdapter(CadSQL, Conex) 'Extrae registros en el 1er DataTable del DataSet(DSemp) DAempleado.Fill(DSemp, "ListaProductos") 'Enlaza Grid a los registros dentro del DataSet Grid1.DataSource = DSemp Grid1.DataMember = "ListaProductos" 'Dos formas de referenciar a los datos dentro de un mismo DataTable c = DSemp.Tables("ListaProductos").Columns.Count 'Total de campos(columnas) de consulta f = DSemp.Tables(0).Rows.Count 'Total de filas de consulta SQL 'Muestra calculos obtenidos desde el DataSet With ListBox1.Items .Clear() .Add(" RESULTADOS:") .Add("Total de Campos: " + c.ToString) .Add(" Lista Campos >>") For H = 0 To c - 1 .Add(Str(H + 1) + ". " + DSemp.Tables(0).Columns(H).Caption) Facultad de Estudios Tecnológicos 18 Next .Add(" ") .Add("Total de Reg: " + f.ToString) End With 'Libera memoria de objetos OLEDB utilizados DSemp = Nothing DAempleado = Nothing 8. Incluya un botón extra al form y en su evento Clic usted programe una línea con la cual cerrara la conexión hacia la BDD del objeto Conex. 9. Guarde su proyecto y ejecute la aplicación 10. Analice con mucho cuidado las diferencias entre las 3 consultas SQL SELECT y responda las preguntas siguientes: a) De la primera consulta, ¿Por qué no da un error el campo llamado Colones (ya que no existe un campo llamado Colones en ninguna de las tablas)?. ¿Por qué lo permite el SQL? b) En la segunda y tercer consulta, ¿Cómo se denominan a las letras a y b que acompañan a los campos y los nombres de las tablas? c) ¿Cuáles son las diferencias entre los resultados de la 2da y 3er consulta?, Explique APLICACIÓN 2 (FormDataReader): u tilizar u n en tor n o “ Cone ctado a la B DD” para lee r registros de tabl as 11. Incluya un nuevo Form dentro del proyecto. Llámele FormDataReader. Luego elabore el siguiente diseño de controles: 12. Cambie la propiedad Text de controles Button1 a Button3 por: Crear Conexión, Llenar DataReader, Leer Registros, respectivamente. 13. Digite los segmentos de código en los bloque indicados: Importe el espacio de nombres System.Data.OleDb: Imports System.Data.OleDb A nivel local dentro de la clase del form FormDataReader: Facultad de Estudios Tecnológicos 19 'Demostracion de uso de metodos/funciones del DataReader Dim TextSql As String 'consulta SQL Select Dim conexOle As OleDbConnection Dim cmdSelect As OleDbCommand Dim drEmpleado As OleDbDataReader En la subrutina de evento Load del form Button1.Enabled = True Button2.Enabled = False Button3.Enabled = False En subrutina de evento Clic del Button1 'Definiendo conexion actual y activandola Try conexOle = New OleDbConnection(CadConex) 'Crea una nueva conexion conexOle.Open() 'Intenta active la conexion If conexOle.State = ConnectionState.Open Then MsgBox("Conexion creada correctamente y abierta") End If 'Creando un objeto Command "vacio" cmdSelect = New OleDbCommand 'Ajustando botones activos Button1.Enabled = False Button2.Enabled = True Button2.Focus() Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Error al crear Conexion") End Try En evento Clic del Button2 Try 'Escriba consulta SELECT para tabla Empleado TextSql = "select * from Empleado" 'configurando command con instruc SQL dicha por usuario With cmdSelect .CommandText = TextSql .CommandType = CommandType.Text .Connection = conexOle End With 'Ejecuta la instrucción del command y devuelve un objeto DaraReader drEmpleado = cmdSelect.ExecuteReader MsgBox("DataReader listo para ser leido") Button2.Enabled = False Button3.Enabled = True Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Error") End Try Facultad de Estudios Tecnológicos 20 En subrutina de evento Clic del Button3 'Demostrando los metodos de recuperacion de valores del DataReader 'De la consulta SQL ejecutada: Total de.. Dim TC As Integer '.. Campos Dim TF As Integer '.. Registros Dim q As Integer 'Contador usos varios Dim Valores As String 'secuencia valores-Campos de c/fila TF = 0 'inicio (ningun registro) With drEmpleado TC = .FieldCount ListBox1.Items.Add("Total de Campos de Select: " + Str(TC)) ListBox1.Items.Add("NOMBRES DE CAMPOS:") For q = 0 To TC - 1 ListBox1.Items.Add("(" + Str(q + 1) + ") " + .GetName(q)) Next q 'Mostrando el nombre completo de empleado de c/fila almacenado ListBox2.Items.Add("LISTA DE EMPLEADOS:") While drEmpleado.Read() TF = TF + 1 'actualiza conteo registro 'Metodo 1: Usando funcion GetString(Id campo) 'Valores = .GetString(1) + " " + .GetString(2) + " , " + .GetString(3) 'ListBox2.Items.Add(Valores) 'Metodo 2: Usando metodo Item( ) gracias a sobrecarga de metodo Valores = .Item("NomsEmp") + " " + .Item("Ape1Emp") + " " + .Item("Ape2Emp") Valores = .Item(3) + " " + .Item(1) + " " + .Item(2) ListBox2.Items.Add(Valores) End While ListBox2.Items.Add("Total Reg= " + Str(TF)) End With 14. Modifique las propiedades del proyecto para que comience desde el objeto FormDataReader y guarde el proyecto. 15. Ejecute el programa y presione el botón activado para ver la secuencia de pasos de como se activa la conexión, como se crea un Command y como un DataReader permite leer los registros que cumplen el comando SQL Select escrito en la propiedad .CommandText de un Command. 16. Incluya un msgbox(mostrando valor de variable TF) dentro del While que lee cada registro proporcionado por el DataReader. Guarde los cambios y ejecute de nuevo el programa. 17. Usted verá que los registros se van leyendo de uno en uno, en secuencia en una sola dirección. APLICACIÓN 3 (MantenimientoTablas): Como registros de una o dos tablas(relacionadas) dar mantenimiento a 18. Diseñe el siguiente formulario: Facultad de Estudios Tecnológicos 21 DataGridView1 DataGridView2 19. A continuación se presentan las propiedades a modificar: OBJETO DataGrid1 y DataGrid2 Button1 Button2 Button3 Button4 PROPIEDAD Name Text Text Text Text VALOR Grid1 y Grid2 respectivamente CargaDatos y Enlace Definir Relación Definir CommandSQL Actualizar Tablas 20. Digite los codigos siguientes de acuerdo al segmento de bloque indicado Importe el espacios de nombres: Imports System.Data.OleDb Dim Dim Dim Dim Dim A nivel de la clase del Form CadSQL As String 'texto del comando SQL i As Integer 'Contador para estructuras repetitivas Cone As OleDbConnection DAjerar, DAemp As OleDbDataAdapter DScomun As New DataSet En el evento Load del form 'Carga de datos desde 2 tablas relacionadas (uno a varios), y la definicion de esta relacion Facultad de Estudios Tecnológicos 22 'Para demostrar que si se borra un reg de tabla primaria, se borraran en cascada 'reg relacionados en tabla derivada 'Crea una nueva conexion a la BDD de Access Cone = New OleDbConnection(CadConex) Cone.Open() 'Activa la conexion En evento Clic del Button1 Try 'Usa la conexion actual(Cone) para cargar datos de 2 DataAdapter diferentes 'pero los registros resultantes se cargaran DENTRO DE UN UNICO DataSet(DScomun). 'Este DataSet colocara cada retorno de registros en objetos DataTable diferentes 'Cargando datos de tabla1(Tabla principal de la relacion): JerarquiaEmp CadSQL = "select * from JerarquiaEmp" DAjerar = New OleDbDataAdapter(CadSQL, Cone) 'Extrae Esquema/definiciones de las columnas de tabla "JerarquiaEmp" DAjerar.FillSchema(DScomun, SchemaType.Source, "JerarquiaEmp") 'Extrae reg hacia DataTable dentro del DScomun DAjerar.Fill(DScomun, "JerarquiaEmp") 'Cargando datos de tabla2(Tabla secundaria de la relacion): Empleado CadSQL = "select * from Empleado" DAemp = New OleDbDataAdapter(CadSQL, Cone) 'Extrae Esquema/definiciones de las columnas de tabla "Empleado" DAemp.FillSchema(DScomun, SchemaType.Source, "Empleado") 'Extrae reg hacia DataTable dentro del DScomun DAemp.Fill(DScomun, "Empleado") 'Cargo los resultados en grid enlazados a cada DataTable dentro 'de un mismo DataSet comun Grid1.DataSource = DScomun Grid1.DataMember = "JerarquiaEmp" Grid2.DataSource = DScomun Grid2.DataMember = "Empleado" Grid2.Columns(0).ReadOnly = True 'Grid2.Columns(0).Visible = False 'Enlazo un control ListBox con un campo de primera tabla With ListBox1 .DataSource = DScomun.Tables("JerarquiaEmp") .DisplayMember = "NomJerar" 'Campo que muestra .ValueMember = "IdJerar" 'Campo enlace del valor mostrado End With MsgBox("Total de tablas cargadas: " + DScomun.Tables.Count.ToString) Button1.Enabled = False Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.OkOnly, "OCURRIO EXCEPCION") End Try Facultad de Estudios Tecnológicos 23 En evento Clic del Button2 'Prepara pasos para definir relación entre tablas desde el DataSet que los tiene almacenado 'PARA COMENZAR: 'declaro Objetos de clases (DataColumn y ForeignKeyConstraint) para establecer 'relacion(primaria - secundaria) entre las 2 tablas: JerarquiaEmp y Empleado Dim dcT1, dcT2 As DataColumn 'Definic Pura de CampoTabla en ambas tablas 'definicion completa de todos los campos(primarios y secundarios) de c/tabla Dim dcJerar(2), dcEmp(2) As DataColumn Dim FKJerarEmp As ForeignKeyConstraint '1: extraido definicion del campo IdJerar de ambas DataTable porque 'es el campo que permite relacion (uno a varios) dcT1 = DScomun.Tables("JerarquiaEmp").Columns("IdJerar") dcT2 = DScomun.Tables("Empleado").Columns("IdJerar") 'Defino conjunto de campos (DataColumn) que hacen la 'llave(primaria) en c/tabla relacionada dcJerar(0) = dcT1 dcEmp(0) = DScomun.Tables("Empleado").Columns("IdEmp") dcEmp(1) = dcT2 '2: Defino en objetos DataTable del DataSet Comun quienes son sus 'campos llaves(con sus caracteristicas, en especial si es autonumico) DScomun.Tables("JerarquiaEmp").PrimaryKey = dcJerar With DScomun.Tables("Empleado") .PrimaryKey = dcEmp 'Indica que campo llave(IdEmp) es de solo lectura y autonumerico '.Columns("IdEmp").AutoIncrement = True '.Columns("IdEmp").ReadOnly = True 'MsgBox("AutoIncrementSeed= " + .Columns("IdEmp").AutoIncrementSeed.ToString) End With '3: "explica" la relacion Uno-Varios definiendo un objeto ForeignKeyConstraint FKJerarEmp = New ForeignKeyConstraint(dcT1, dcT2) FKJerarEmp.UpdateRule = Rule.Cascade 'Que actualice en cascada reg relacionados FKJerarEmp.DeleteRule = Rule.Cascade 'Que borre en cascada reg relacionados '4: agrega la relacion anterior al DataSet comun DScomun.Tables("Empleado").Constraints.Add(FKJerarEmp) Button2.Enabled = False En el Button3 en su evento Clic 'Preparo los 3 command minimos que necesita la conexion para actualizar registros. 'Estos command son las 3 instrucciones SQL: Update, Insert y Delete Facultad de Estudios Tecnológicos 24 'Fijese MUY BIEN CADA LINEA, LA SECUENCIA GENERAL Y LOS COMENTARIOS RESPECTIVOS Try 'Defino comando SQL para que actualice(update) registros en tabla "Empleado" Dim cmdActuali As New OleDbCommand("update Empleado set Ape1Emp=?,Ape2Emp=?,NomsEmp=?,DirecEmp=?,TelCasaEmp=? where IdEmp=? and IdJerar=?") 'Le Agrego parametros que necesita instrucc SQL UPDATE anterior cmdActuali.Parameters.Add(New OleDbParameter("@Ape1Emp", OleDb.OleDbType.Char, 10, "Ape1Emp")) cmdActuali.Parameters.Add(New OleDbParameter("@Ape2Emp", OleDb.OleDbType.Char, 10, "Ape2Emp")) cmdActuali.Parameters.Add(New OleDbParameter("@NomsEmp", OleDb.OleDbType.Char, 10, "NomsEmp")) cmdActuali.Parameters.Add(New OleDbParameter("@DirecEmp", OleDb.OleDbType.Char, 50, "DirecEmp")) cmdActuali.Parameters.Add(New OleDbParameter("@TelCasaEmp", OleDb.OleDbType.Char, 15, "TelCasaEmp")) cmdActuali.Parameters.Add(New OleDbParameter("@IdEmp", OleDb.OleDbType.BigInt, 2, "IdEmp")) cmdActuali.Parameters.Add(New OleDbParameter("@IdJerar", OleDb.OleDbType.Integer, 2, "IdJerar")) cmdActuali.Connection = Cone 'Conexion abierta a la cual esta enlazado DataAdapter que este comando 'Defino comando SQL para que agregue(insert) nuevos registros en tabla "Empleado" 'Dim cmdActuali As New OleDbCommand("update Empleado set Ape2Emp=? where IdEmp=? and IdJerar=?") Dim cmdNuevo As New OleDbCommand("insert into Empleado(Ape1Emp,Ape2Emp,NomsEmp,IdJerar, DirecEmp,TelCasaEmp) values (?,?,?,?,?,?)") 'Le Agrego parametros que necesita instrucc SQL UPDATE anterior With cmdNuevo.Parameters .Add(New OleDbParameter("@Ape1Emp", OleDb.OleDbType.Char, 10, "Ape1Emp")) .Add(New OleDbParameter("@Ape2Emp", OleDb.OleDbType.Char, 10, "Ape2Emp")) .Add(New OleDbParameter("@NomsEmp", OleDb.OleDbType.Char, 10, "NomsEmp")) .Add(New OleDbParameter("@IdJerar", OleDb.OleDbType.Integer, 2, "IdJerar")) .Add(New OleDbParameter("@DirecEmp", OleDb.OleDbType.Char, 50, "DirecEmp")) .Add(New OleDbParameter("@TelCasaEmp", OleDb.OleDbType.Char, 15, "TelCasaEmp")) End With cmdNuevo.Connection = Cone 'Conexion abierta a la cual esta enlazado DataAdapter que este comando 'Defino comando SQL para que borre registros en tabla "Empleado" Dim cmdBorrar As New OleDbCommand("delete from Empleado where IdEmp=?") cmdBorrar.Parameters.Add(New OleDbParameter("@IdEmp", OleDb.OleDbType.Integer, 2, "IdEmp")) Facultad de Estudios Tecnológicos 25 cmdBorrar.Connection = Cone 'Conexion abierta a la cual esta enlazado DataAdapter que este comando 'Asigno Command configurados al DataAdapter DAemp.DeleteCommand = cmdBorrar DAemp.UpdateCommand = cmdActuali DAemp.InsertCommand = cmdNuevo Button3.Enabled = False Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.OkOnly, "OCURRIO EXCEPCION") End Try Del Button4 y su evento Clic 'Actualizacion de reg modificados en tabla (Empleados: Tabla secundaria de la relacion) 'hacia la BDD. 'Procede a realizar la actualizac(Nuevo,Modificac y Borrado) de registros de Empleados solamente DAemp.Update(DScomun, "Empleado") Cone.Close() 'Cierro la conexion actual MsgBox("Actualizaciones de la BDD finalizadas") 21. Guarde los cambios del proyecto. 22. Ahora ejecute el proyecto y de clic solamente en el 1er botón (cargar de datos y enlace). Verá que se muestran los registros de 2 tablas de la BDD (JerarquiaEmp y Empleado, las cuales según la BDD están relacionadas). Además observe que en el ListBox1 se muestran los mismos registros de la 1er tabla (JerarquiaEmp). Lo anterior porque la propiedad DataSource y DataMember de cada control se enlazan al 1er DataTable del DataSet DSComun. 23. Ahora modifique en el Grid2 algunos de los datos de empleados como apellidos, nombre, etc. Incluso busque la ultima fila e incluya datos de nuevos empleados (teniendo cuidado de cumplir la integridad referencial de los campos llaves foráneas). Finalice la aplicación y luego busque el archivo de la BDD. Observe el contenido de los empleados que modificó en la aplicación y vera que no hizo ningún cambio. ¿Por qué? porque ADO.NET funciona de una manera desconectada y solo se conecta a la BDD para hacer una copia de registros, ejecutar funciones, actualizar apropiadamente los registro de tablas y otros, para luego desconectarse. 24. Ejecute de nuevo la aplicación y repita el paso anterior. De clic en el Button4 después modificar los datos en el Grid2. Verá que NET activa una excepcion (un error) para avisar que no se han establecidos los parámetros de los Command que posee el DataSet para saber como realizar las actualizaciones SQL (Insert, Update y Delete). Sin estos command dentro de un DataSet, este no sabe como relacionar los datos de registros (almacenados en sus DataTable y los cuales se han podido modificar o eliminar) con los registros “reales” de las tablas en la BDD 25. De nuevo vuelva a ejecutar el programa, pero esta vez realice los pasos según este algoritmo: a) Clic en el 1er botón para así enlazarse a la BDD y cargar los datos de las 2 tablas, para mostrarlos en los Grid‟s. Facultad de Estudios Tecnológicos 26 b) Clic en el segundo y tercer botón en ese orden c) Ubíquese en el Grid2, recorra a los registros de empleados y fíjese el cargo que tiene cada uno. d) Modifique datos de empleados existentes. Además vaya a fila del último empleado y observe que al querer incluir un nuevo empleado, el campo auto numérico sigue el próximo número de la secuencia. Cuide los valores de campos llaves para así mantener la integridad referencial. Por ultimo, apunte el IdEmp de algunos empleados antes de que los borre. e) Finalizadas las modificaciones, toque el Button4. 26. Gracias al código ejecutado por Button2 y Button3 se establecen en el DataSet (DScomun) las relaciones entre las tablas (JerarquiEmp y Empleado) y restricciones de sus campos. Y en especial se definen los Command con las instrucciones SQL (Insert, Update y Delete) que le permitirá coordinarse con la BDD para modificar apropiadamente los registros de sus tablas. 27. Como ya se ha dado cuenta, cuando usted modifica, elimina o agrega registros en el Grid2 y luego da clic en Button4, los cambios son realizados en la base de datos siempre y cuando siga los pasos del punto 25. Esto mismo no ocurre si usted modifica, elimina o agrega registros en el Grid1. Realice las modificaciones necesarias para efectuar estas 3 operaciones en la tabla JerarquiaEmp. V. ANALISIS DE RESULTADOS MiniProyecto: Crear un programa para dar mantenimiento a una bases de datos, de la empresa “El Buen Pastor” la cual es una distribuidora a nivel de Latinoamérica de artículos de todo tipo para iglesias. El programa debe ser capaz de mostrar las ventas totales del día, los envíos realizados a cada país y la cantidad de productos También debe permitir que el administrador ingrese pedidos, tiendas clientes y todos los datos de esta, nuevos artículo, precio, etc. Tome en cuenta que la distribuidora posee dos bodegas diferentes y no hace envíos de menos de 500 dólares, a menos que se cobre un recargo. El programa también debe trabajar con una cantidad de autos disponibles para los envíos, teniendo en cuenta que habrán envíos grandes (Furgones), Medianos (Camionetas) y pequeños (autos pequeños). Se tomara en cuenta el diseño de la base de datos, para esta tarea formar grupos según la cantidad indicada por su docente. Facultad de Estudios Tecnológicos 27