ADO.NET Introducción La mayoría de las aplicaciones escritas en Visual Basic y Visual C# giran en torno a la lectura y actualización de información de bases de datos. Para permitir la integración de datos en aplicaciones distribuidas y escalables, Visual Studio .NET es compatible con una nueva generación de tecnología de acceso a datos: ADO.NET. El problema es comunicar un programa o aplicación con una base de datos y más que comunicar se pretende que el programa o aplicación realice una serie de procesos u operaciones con la base de datos o mejor aun con el conjunto de tablas que contiene una base de datos. La primera nota a recordar es que una base de datos puede estar físicamente en el servidor y en algún fólder o directorio del disco duro de dicha maquina. Otra cosilla que debemos recordar es que así como existen servidores de paginas (Web Server), servidores de correo (Mail Server), servidores de ftp (ftp Server),..., también existen servidores de bases de datos (DataBase Server), los más comunes son el SqlServer de Microsoft, Oracle, MySql, y muchos más, estos servidores también pueden crear, administrar y procesar una base de datos. El modo de comunicación entre nuestra aplicación y la base de datos implica que ambos manejen un lenguaje de programación común, es decir no se puede mandar una instrucción en C# .net, o en visual Basic .net o en Basic o pascal...o en cualquier otro lenguaje, a la base de datos y además esperar que esta última la entienda. Para entender esto, una razón muy sencilla es que la base de datos tendría que conocer o comprender todos los lenguajes de programación, ahora dime, no sería más fácil que exista un lenguaje común...?, entonces para resolver este problema de comunicación es que se usa un lenguaje común de bases de datos que tanto los lenguajes de programación existentes como las bases de datos entienden, este lenguaje común de bases de datos es el SQL (Structured Query Languaje) o lenguaje estructurado de consultas. La pregunta es ahora como mandamos las instrucciones SQL a la base de datos, la respuesta es mediante los OBJETOS ADO.NET, las cuales proporcionan acceso coherente a orígenes de datos como Microsoft SQL Server, así como a orígenes de datos expuestos mediante OLE DB y XML. En la actualidad ADO.NET ya es parte del .NET Framework, esto quiere decir que es, de alguna manera, parte del sistema operativo y no más un redistribuible de 4 ó 5 MB que se necesita alojar junto al cliente o junto al instalador de una aplicación. Esto significa que nosotros, como desarrolladores, estaremos enfocados más al acceso a datos y a la lógica para manipular estos datos, y no tendremos porqué preocuparnos en cómo a los clientes la librería. La mayoría de las aplicaciones necesitan algún mecanismo de acceso a datos. Si está creando una aplicación nueva, dispone de tres opciones excelentes para obtener acceso a los datos: ADO.NET, ADO y OLE DB. Si necesita modificar el mecanismo de acceso a datos de una aplicación existente, debería seguir utilizando la tecnología actual de acceso a datos de la aplicación por cuestiones de mantenimiento. Si usted prevé que la aplicación va a tener un ciclo de vida largo, entonces debe considerar la posibilidad de rediseñar la tecnología de acceso a datos de la aplicación y utilizar ADO.NET en aplicaciones administradas o ADO en aplicaciones nativas. A largo plazo, el uso de las tecnologías más modernas de acceso a datos reduce el tiempo de desarrollo, simplifica el código y proporciona un rendimiento excelente. Acceso a datos con ADO.NET • ADO.NET es una tecnología de acceso a datos que se basa en los objetos ADO (Objetos de Datos ActiveX) anteriores. • Es una manera nueva de acceder a los datos construida sobre ADO. ADO.NET puede coexistir con ADO. • También podemos decir que ADO.NET es un conjunto de clases que exponen servicios de acceso a datos al programador de .NET. • ADO.NET proporciona un conjunto variado de componentes para crear aplicaciones distribuidas de uso compartido de datos. Forma parte integral de .NET Framework, y proporciona acceso a datos relacionales, datos XML y datos de aplicaciones. • ADO.NET es compatible con diversas necesidades de programación, incluida la creación de clientes de bases de datos clientes y objetos empresariales de nivel medio utilizados por aplicaciones, herramientas, lenguajes o exploradores de Internet. • ADO.NET utiliza un modelo de acceso pensado para entornos desconectados. Esto quiere decir que la aplicación se conecta al origen de datos, hace lo que tiene que hacer, por ejemplo seleccionar registros, los carga en memoria y se desconecta del origen 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 Excel. • ADO.NET utiliza XML como el formato para transmitir datos desde y hacia su base de datos y su aplicación Web. • Hay 3 espacios de nombres que se importará en un formulario Web o formulario Windows si esta usando ADO.NET: o System.Data. o System.Data.SqlClient. o System.Data.OleDb. Espacios de nombres para datos en el .NET Framework Entre los espacios de nombres de .NET Framework relativos a datos y XML se incluyen: Espacio de Nombre System.Data System.Data.Common System.Xml System.Data.OleDb System.Data.SqlClient System.Data.SqlTypes System.Data.OleDb System.Data.OracleClient Descripción Consiste en las clases que constituyen la arquitectura ADO.NET, que es el método primario para tener acceso a los datos de las aplicaciones administradas. La arquitectura ADO.NET permite crear componentes que administran eficientemente datos procedentes de múltiples orígenes. ADO.NET también proporciona las herramientas necesarias para solicitar, actualizar y reconciliar datos en aplicaciones distribuidas. Contiene las clases que comparten los proveedores de datos .NET Framework. Dichos proveedores describen una colección de clases que se utiliza para obtener acceso a un origen de datos, como una base de datos, en el espacio administrado. Clases que proporcionan funcionalidad basada en estándares para procesar código XML. 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. 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. 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. Clases que componen el proveedor de datos de .NET Framework para OLE DB. Estas clases permiten el acceso a orígenes de datos ODBC en el espacio administrado. 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. Componentes de ADO.NET Existen dos componentes de ADO.NET que se pueden utilizar para obtener acceso a datos y manipularlos: • Proveedores de datos de .NET Framework • DataSet Proveedores de datos de .NET Framework Los proveedores de datos de .NET Framework son componentes diseñados explícitamente para la manipulación de datos y el acceso rápido a datos de sólo lectura y sólo avance. Objeto Descripción Objeto SQL Server Objeto para un origen OLEDB Connection Establece una conexión a un origen de datos determinado. SqlConnection OleDBConnection Command Permite tener acceso a comandos de base de datos para devolver datos, modificar datos, ejecutar procedimientos almacenados y enviar o recuperar información sobre parámetros. SqlCommand OleDBCommand DataReader Proporciona un acceso rápido, hacia adelante y de solo lectura (¿parecido al recorset no?). SqlDataReader OleDBDataReader DataAdapter Proporciona el puente entre el objeto DataSet y el origen de datos. El DataAdapter utiliza objetos Command para ejecutar comandos SQL en el origen de datos tanto para cargar el DataSet con datos como para reconciliar en el origen de datos los cambios aplicados a los datos incluidos en el DataSet. SqlDataAdapter OleDBDataAdapter Además de las clases principales citadas en la tabla anterior, los proveedores de datos de .NET Framework también incluyen las que se enumeran en la tabla siguiente. Objeto Transaction CommandBuilder ConnectionStringBuilder Parameter Exception Error ClientPermission Descripción Permite incluir comandos en las transacciones que se realizan en el origen de datos. La clase base para todos los objetos Transaction es DbTransaction. Un objeto auxiliar que genera automáticamente las propiedades de comando de un DataAdapter o que obtiene de un procedimiento almacenado información acerca de parámetros con la que puede rellenar la colección Parameters de un objeto Command. La clase base para todos los objetos CommandBuilder es DbCommandBuilder. Un objeto auxiliar que proporciona un modo sencillo de crear y administrar el contenido de las cadenas de conexión utilizadas por los objetos Connection. La clase base para todos los objetos ConnectionStringBuilder es DbConnectionStringBuilder. Define los parámetros de entrada, salida y valores devueltos para los comandos y procedimientos almacenados. La clase base para todos los objetos Parameter es DbParameter. Se devuelve cuando se detecta un error en el origen de datos. En el caso de que el error se detecte en el cliente, los proveedores de datos de .NET Framework inician una excepción de .NET Framework. La clase base para todos los objetos Exception es DbException. Expone la información relacionada con una advertencia o error devueltos por un origen de datos. Se proporciona para los atributos de seguridad de acceso a código de los proveedores de datos de .NET Framework. La clase base para todos los objetos ClientPermission es DBDataPermission. Componente u objeto Conjunto de datos • DataSet • DataTable • DataColumm • DataRow • DataRelation • Constraint Adaptador de datos • OleDbDataAdapter • SqlDataAdapter • OdbcDataAdapter • OracleDataAdapter • SqlDataReader • OleDbDataReader • OdbcDataReader • OracleDataReader Conexión de datos • SqlConnection • OleDbConnection • OdbcConnection • OracleConnection Formulario Windows Forms Página de Formulario Web Forms Detalle Los conjuntos de datos almacenan datos en una memoria caché desconectada. La estructura de un conjunto de datos es similar a la de una base de datos relacional; expone un modelo jerárquico de tablas, filas y columnas. Además, contiene restricciones y relaciones definidas para el conjunto de datos. Los adaptadores de datos son una parte integral de los proveedores administrados por ADO.NET, que son el conjunto de objetos que se utiliza para la comunicación entre un origen de datos y un conjunto de datos. Esto significa leer datos de una base de datos para un conjunto de datos y, a continuación, volver escribir en la base de datos los datos modificados del conjunto de datos. Sin embargo, un adaptador de datos puede trasladar datos entre cualquier origen y un conjunto de datos. Por ejemplo, podría haber un adaptador que trasladara datos entre un servidor Microsoft Exchange y un conjunto de datos. Para trasladar datos entre un almacén de datos y una aplicación, en primer lugar deberá tener una conexión con el almacén de datos. Windows Forms es la nueva plataforma de desarrollo de aplicaciones para Microsoft Windows, basada en .NET Framework. Este marco de trabajo proporciona un conjunto de clases claro, orientado a objetos y ampliable, que permite desarrollar complejas aplicaciones para Windows. Además, los formularios Windows Forms pueden actuar como interfaz de usuario local en una solución distribuida de varios niveles. Las páginas de formularios Web Forms pueden usarse para crear páginas Web programables que sirvan como interfaz de usuario de las aplicaciones Web. Este tipo de páginas presenta la información al usuario en cualquier explorador o dispositivo cliente e implementa lógica de aplicación mediante el código de la parte servidor. La salida de las páginas de formularios Web Forms puede contener casi cualquier lenguaje compatible con HTTP, incluidos HTML, XML, WML y ECMAScript (JScript, JavaScript). DataSet El DataSet de ADO.NET está expresamente diseñado para el acceso a datos independientemente del origen de datos. Como resultado, se puede utilizar con múltiples y distintos orígenes de datos, con datos XML o para administrar datos locales de la aplicación. El DataSet contiene una colección de uno o más objetos DataTable formados por filas y columnas de datos, así como información sobre claves principales, claves externas, restricciones y relaciones relativas a los datos incluidos en los objetos DataTable. • Un objeto DataSet representa un esquema (o una base de datos entera o un subconjunto de una). Puede contener las tablas y las relaciones entre esas tablas. o Un objeto DataTable representa una sola tabla en la base de datos. Tiene un nombre, filas, y columnas. - Un objeto DataView "se sienta sobre" un DataTable y ordena los datos (como una cláusula "order by" de SQL) y, si se activa un filtro, filtra los registros (como una cláusula "where" del SQL). Para facilitar estas operaciones se usa un índice en memoria. Todas las DataTables tienen un filtro por defecto, mientras que pueden ser definidos cualquier número de DataViews adicionales, reduciendo la interacción con la base de datos subyacente y mejorando así el desempeño. - Un DataColumn representa una columna de la tabla, incluyendo su nombre y tipo. - Un objeto DataRow representa una sola fila en la tabla, y permite leer y actualizar los valores en esa fila, así como la recuperación de cualquier fila que esté relacionada con ella a través de una relación de clave primaria - clave extranjera. - Un DataRowView representa una sola fila de un DataView, la diferencia entre un DataRow y el DataRowView es importante cuando se está interactuando sobre un resultset. o Un DataRelation es una relación entre las tablas, tales como una relación de clave primaria - clave ajena. Esto es útil para permitir la funcionalidad del DataRow de recuperar filas relacionadas. o Un Constraint describe una propiedad de la base de datos que se debe cumplir, como que los valores en una columna de clave primaria deben ser únicos. A medida que los datos son modificados cualquier violación que se presente causará excepciones. Un DataSet es llenado desde una base de datos por un DataAdapter cuyas propiedades Connection y Command que han sido iniciados. Sin embargo, un DataSet puede guardar su contenido a XML (opcionalmente con un esquema XSD), o llenarse a sí mismo desde un XML, haciendo esto excepcionalmente útil para los servicios Web, computación distribuida, y aplicaciones ocasionalmente conectadas. En el diagrama siguiente se ilustra la relación entre un proveedor de datos de .NET Framework y un DataSet. Arquitectura de ADO.NET Imports System.Data.OleDb Imports System.Data.SqlClient Imports System.Data Public Class SQLServer2005 Private conexion As SqlConnection Private cadenaConexion As String ' Cadena de conexión con autentificación de SQL Server Public Function abrirConexion(ByVal fuenteDatos As String, _ ByVal catalogo As String, _ ByVal usuario As String, _ ByVal clave As String) As SqlConnection cadenaConexion = "data source=" & fuenteDatos & ";" & _ "inicial catalog=" & catalogo & ";" & _ "user id=" & usuario & ";" & _ "password=" & clave Try 'Abrimos la conexión conexion = New Data.SqlClient.SqlConnection(cadenaConexion) conexion.Open() Catch ex As Exception MessageBox.Show("Error al abrir la conexión:" & vbCrLf & ex.Message) End Try Return conexion End Function ' Cadena de conexión con autentificación de Windows Public Function abrirConexion(ByVal servidor As String, _ ByVal baseDatos As String, _ ByVal integratedSecurity As String) As SqlConnection cadenaConexion = "Server=" & servidor & ";" & _ "DataBase=" & baseDatos & ";" & _ "integrated security=" & integratedSecurity & ";" Try 'Abrimos la conexión conexion = New Data.SqlClient.SqlConnection(cadenaConexion) conexion.Open() Catch ex As Exception MessageBox.Show("Error al abrir la conexión:" & vbCrLf & ex.Message) End Try Return conexion End Function Public Sub cerrarConexion() Try 'Cerramos la conexión conexion.Close() Catch ex As Exception MessageBox.Show("Error al cerrar la conexión:" & vbCrLf & ex.Message) Exit Sub End Try End Sub End Class Imports System.Data.OleDb Imports System.Data.SqlClient Imports System.Data Public Class Alumno Private Private Private Private Private Private Private Private Private conector As New SQLServer2005 conexion As SqlConnection = Nothing comandoSQL As SqlCommand = Nothing parametroSQL As SqlParameter da As SqlDataAdapter ds As DataSet dt As DataTable dr As DataRow consultaSQL As String Private servidor As String = "XQPCUEVA\SQLEXPRESS2005" Private baseDatos As String = "EjemploVB" Private seguridadIntegrada As String = "SSPI" ' Consultar alumnos por CI Public Function consultarAlumno(ByVal cedula As Integer) As DataSet ' Se abre la conexion ' Si la conexión es local se puede cambiar el nombre del servidor por (local) ' conexion = helper.abrirConexion("(local)\SQLEXPRESS", "EjemploVB", "YES") conexion = conector.abrirConexion(servidor, baseDatos, seguridadIntegrada) ' (Nombre del Stored Procedure, Conexion) comandoSQL = New SqlCommand("consultarAlumno", conexion) ' Tipo de Comando = Stored Procedure comandoSQL.CommandType = Data.CommandType.StoredProcedure ' Instancia del paramentro parametroSQL = New SqlParameter("@cedula", cedula) ' Pase del parametro comandoSQL.Parameters.Add(parametroSQL) ' Ejecución del Stored Procedure comandoSQL.ExecuteNonQuery() da = New SqlDataAdapter(comandoSQL) 'da = New SqlDataAdapter 'da.SelectCommand = comandoSQL 'Dim comdBuilder As New SqlCommandBuilder(da) 'Añadiríamos esta línea si la tabla tiene clave principal 'autoincremental para poder actualizar posteriormente da.MissingSchemaAction = MissingSchemaAction.AddWithKey '(Añadir con clave) Try ds = New DataSet 'Cargamos el DataSet da.Fill(ds, "Alumno") Catch ex As Exception MessageBox.Show("Error al cargar el DataSet:" & vbCrLf & ex.Message) Finally If conexion IsNot Nothing AndAlso conexion.State <> ConnectionState.Closed Then ' Cerrar conexion conexion.Close() End If End Try Return ds End Function ' Consultar cantidad de alumnos por CI Public Function cantidadAlumnos() As Integer Dim cantidad As Integer ' Se abre la conexion conexion = conector.abrirConexion(servidor, baseDatos, seguridadIntegrada) ' (Nombre Stored Procedure, Conexion) comandoSQL = New SqlCommand("cantidadAlumnos", conexion) ' Tipo de Comando = Stored Procedure comandoSQL.CommandType = Data.CommandType.StoredProcedure ' Ejecución del Stored Procedure cantidad = comandoSQL.ExecuteScalar() If conexion IsNot Nothing AndAlso conexion.State <> ConnectionState.Closed Then ' Cerrar conexion conexion.Close() End If Return cantidad End Function Public Sub agregarAlumno(ByVal cedula As Integer, _ ByVal nombre As String, _ ByVal edad As Integer) conexion = conector.abrirConexion(servidor, baseDatos, seguridadIntegrada) ' (Nombre Stored Procedure, Conexion) comandoSQL = New SqlCommand("agregarAlumno", conexion) ' Tipo de Comando = Stored Procedure comandoSQL.CommandType = Data.CommandType.StoredProcedure ' Otra forma de pasar parametro sin instanciar el objeto SqlParameter comandoSQL.Parameters.Add("@cedula", SqlDbType.Int) comandoSQL.Parameters("@cedula").Value = cedula comandoSQL.Parameters.Add("@nombre", SqlDbType.NChar) comandoSQL.Parameters("@nombre").Value = nombre comandoSQL.Parameters.Add("@edad", SqlDbType.Int) comandoSQL.Parameters("@edad").Value = edad ' Ejecución del Stored Procedure comandoSQL.ExecuteNonQuery() conexion.Close() End Sub End Class Imports System.Data Public Class frmIUGT Private consultas As New Alumno Private ds As DataSet Private Sub BtnCargarGrid_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnCargarGrid.Click ds = consultas.listarAlumnos() dgvPrueba.DataSource = ds.Tables("Alumno") End Sub Private Sub btnConsultarCedula_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConsultarCedula.Click If IsNumeric(Me.txtCI.Text) Then ds = consultas.consultarAlumno(Me.txtCI.Text) dgvPrueba.DataSource = ds.Tables("Alumno") Else MessageBox.Show("Ingrese un valor de CI válido" & vbCrLf) End If End Sub Private Sub btnCantidad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCantidad.Click Dim cantidad As Integer cantidad = consultas.cantidadAlumnos Me.lblCantidadAlumnos.Text = "La cantidad de alumno es: " & cantidad.ToString End Sub Private Sub btnAgregar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAgregar.Click 'consultas.agregarAlumno(Me.txtCI.Text, Me.txtNombre.Text, Me.txtEdad.Text) consultas.insertarAlumno(Integer.Parse(Me.txtCI.Text), Me.txtNombre.Text, Integer.Parse(Me.txtEdad.Text)) End Sub Public Sub New() ' Llamada necesaria para el Diseñador de Windows Forms. InitializeComponent() ' Agregue cualquier inicialización después de la llamada a InitializeComponent(). ds = consultas.listarAlumnos() cmbEjemplo.DataSource = ds.Tables("Alumno") cmbEjemplo.DisplayMember = "Nombre" cmbEjemplo.ValueMember = "CI" cmbEjemplo.DropDownStyle = ComboBoxStyle.DropDownList End Sub End Class