ADO.NET ADO.NET proporciona acceso coherente a orígenes de datos como SQL Server y XML, así como a orígenes de datos expuestos mediante OLE DB y ODBC. Las aplicaciones de consumidor que comparten datos pueden utilizar ADO.NET para conectar a estos orígenes de datos y recuperar, controlar y actualizar los datos contenidos. ADO.NET separa el acceso a datos de la manipulación de datos y crea componentes discretos que se pueden utilizar por separado o conjuntamente. ADO.NET incluye proveedores de datos .NET Framework para conectarse a una base de datos, ejecutar comandos y recuperar resultados. Los resultados se procesan directamente o se colocan en un objeto DataSet de ADO.NET con el fin de exponerlos al usuario para un propósito específico, combinados con datos de varios orígenes, o de pasarlos entre niveles. El objeto DataSet de ADO.NET también puede utilizarse independientemente de un proveedor de datos .NET Framework para administrar datos que son locales de la aplicación o que proceden de un origen XML. Las clases de ADO.NET se encuentran en System.Data.dll y se integran con las clases de XML incluidas en System.Xml.dll. Para obtener un ejemplo de código muestra que se conecta a una base de datos, recupera datos de ésta y los muestra en la ventana de la consola, vea Ejemplos de código de ADO.NET. Arquitectura de ADO.NET Los proveedores de datos .NET Framework son componentes diseñados explícitamente para la manipulación de datos y el acceso rápido a datos de solo lectura y solo avance. El objeto Connection proporciona conectividad a un origen de datos. El objeto 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. DataReader proporciona un flujo de datos de alto rendimiento desde el origen de datos. Por último, el objeto DataAdapter proporciona el puente entre el objeto DataSet y el origen de datos. DataAdapter utiliza objetos Command para ejecutar comandos SQL en el origen de datos tanto para cargar DataSet con datos y reconciliar en el origen de datos los cambios aplicados a los datos incluidos en el DataSet. 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. 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 de relación relacionada con los datos incluidos en los objetos DataTable. 1 Elegir un DataReader o un DataSet A la hora de decidir si su aplicación debe utilizar un DataReader o un DataSet debe tener en cuenta el tipo de funcionalidad que su aplicación requiere. Use un DataSet para hacer lo siguiente: • • • • Almacene datos en la memoria caché de la aplicación para poder manipularlos. Si solamente necesita leer los resultados de una consulta, el DataReader es la mejor elección. Utilizar datos de forma remota entre un nivel y otro o desde un servicio Web XML. Interactuar con datos dinámicamente, por ejemplo para enlazar con un control de Windows Forms o para combinar y relacionar datos procedentes de varios orígenes. Realizar procesamientos exhaustivos de datos sin necesidad de tener una conexión abierta con el origen de datos, lo que libera la conexión para que la utilicen otros clientes. Si no necesita la funcionalidad proporcionada por el DataSet, puede mejorar el rendimiento de su aplicación si utiliza el DataReader para devolver sus datos de solo avance y de solo lectura. Aunque DataAdapter utiliza DataReader para rellenar el contenido de un DataSet al utilizar el DataReader puede mejorar el rendimiento porque no usará la memoria que utilizaría el DataSet, además de evitar el procesamiento necesario para crear y rellenar el contenido de DataSet. LINQ y ADO.NET Actualmente, muchos programadores empresariales deben usar dos (o más) lenguajes de programación: un lenguaje de alto nivel para las capas de presentación y lógica empresarial (como Visual C# o Visual Basic) y un lenguaje de consulta para interactuar con la base de datos (como Transact-SQL). Esto requiere que el programador tenga conocimientos de varios idiomas para ser efectivo y también causa discrepancias de idiomas en el entorno de desarrollo. Por ejemplo, una aplicación que utiliza API de acceso a datos para ejecutar una consulta en una base de datos especifica la consulta como un literal de cadena usando comillas. Esta cadena de consulta es ilegible y no se comprueba si contiene errores, tales como una sintaxis no válida o si existen las columnas o las filas a las que hace referencia. No hay ninguna comprobación de tipo de los parámetros de consulta y tampoco hay compatibilidad con IntelliSense. Language-Integrated Query (LINQ) permite a los programadores formar consultas basadas en conjuntos en el código de su aplicación, sin tener que usar un lenguaje de consulta independiente. Se puede escribir consultas de LINQ en varios orígenes de datos enumerables (es decir, un origen de datos que implementa la interfaz IEnumerable), como estructuras de datos en memoria, documentos XML, bases de datos SQL y objetos DataSet. 2 Aunque esos orígenes de datos enumerables se implementan de varias formas, todos revelan las mismas construcciones de lenguaje y sintaxis. Como las consultas se pueden formar en el lenguaje de programación mismo, no es necesario utilizar otro lenguaje de consultas que esté incrustado como literales de cadena que el compilador no pueda entender o comprobar. La integración de consultas en el lenguaje de programación también permite a los programadores de Visual Studio ser más productivos proporcionando comprobación de sintaxis y tipo en tiempo de compilación e IntelliSense. Estas características reducen la necesidad de depuración y corrección de errores de consultas. La transferencia de datos de las tablas de SQL a objetos de memoria a menudo es una tarea tediosa y propensa a errores. El proveedor de LINQ implementado por LINQ to DataSet y LINQ to SQL convierte el origen de datos en recopilaciones de objetos basadas en IEnumerable. El programador siempre ve los datos como una recopilación de IEnumerable cuando se realiza la consulta y la actualización. Se proporciona compatibilidad completa con IntelliSense para escribir consultas en esas colecciones. Existen tres tecnologías Language-Integrated Query (LINQ) de ADO.NET independientes: • • • LINQ to DataSet LINQ to SQL LINQ to Entities. LINQ to DataSet proporciona consultas más ricas y optimizadas de DataSet, LINQ to SQL permite consultar directamente los esquemas de base de datos de SQL Server y LINQ to Entities permite consultar un Entity Data Model. 3 Ejemplo: Proveedor de Datos para SQL Server Imports System Imports System.Data Imports System.Data.SqlClient Public Class Program Public Shared Sub Main() Dim connectionString As String = _ "Data Source=(local);Initial Catalog=Northwind;" _ & "Integrated Security=true" Dim queryString As String = _ "SELECT ProductID, UnitPrice, ProductName from dbo.Products " _ & "WHERE UnitPrice > @pricePoint " _ & "ORDER BY UnitPrice DESC;" Dim paramValue As Integer = 5 Using connection As New SqlConnection(connectionString) Dim command As New SqlCommand(queryString, connection) command.Parameters.AddWithValue("@pricePoint", paramValue) Try connection.Open() Dim dataReader As SqlDataReader = _ command.ExecuteReader() Do While dataReader.Read() Console.WriteLine( _ vbTab & "{0}" & vbTab & "{1}" & vbTab & "{2}", _ dataReader(0), dataReader(1), dataReader(2)) Loop dataReader.Close() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.ReadLine() End Using End Sub End Class 4 Ejemplo: Proveedor de Datos para OLEDB Imports System Imports System.Data Imports System.Data.OleDb Public Class Program Public Shared Sub Main() Dim connectionString As String = _ "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _ & "c:\Data\Northwind.mdb;User Id=admin;Password=;" Dim queryString As String = _ "SELECT ProductID, UnitPrice, ProductName from Products " _ & "WHERE UnitPrice > ? " _ & "ORDER BY UnitPrice DESC;" Dim paramValue As Integer = 5 Using connection As New OleDbConnection(connectionString) Dim command As New OleDbCommand(queryString, connection) command.Parameters.AddWithValue("@pricePoint", paramValue) Try connection.Open() Dim dataReader As OleDbDataReader = _ command.ExecuteReader() Do While dataReader.Read() Console.WriteLine( _ vbTab & "{0}" & vbTab & "{1}" & vbTab & "{2}", _ dataReader(0), dataReader(1), dataReader(2)) Loop dataReader.Close() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.ReadLine() End Using End Sub End Class 5 Ejemplo: Proveedor de Datos para ODBC Imports System Imports System.Data Imports System.Data.Odbc Public Class Program Public Shared Sub Main() Dim connectionString As String = _ "Driver={Microsoft Access Driver (*.mdb)};" _ & "Dbq=c:\Data\Northwind.mdb;Uid=Admin;Pwd=;" Dim queryString As String = _ "SELECT ProductID, UnitPrice, ProductName from Products " _ & "WHERE UnitPrice > ? " _ & "ORDER BY UnitPrice DESC;" Dim paramValue As Integer = 5 Using connection As New OdbcConnection(connectionString) Dim command As New OdbcCommand(queryString, connection) command.Parameters.AddWithValue("@pricePoint", paramValue) Try connection.Open() Dim dataReader As OdbcDataReader = _ command.ExecuteReader() Do While dataReader.Read() Console.WriteLine( _ vbTab & "{0}" & vbTab & "{1}" & vbTab & "{2}", _ dataReader(0), dataReader(1), dataReader(2)) Loop dataReader.Close() Catch ex As Exception Console.WriteLine(ex.Message) End Try Console.ReadLine() End Using End Sub End Class 6 Ejemplo: Proveedor de Datos para ORACLE Imports System Imports System.Data Imports System.Data.OracleClient Public Class Program Public Shared Sub Main() Dim connectionString As String = _ "Data Source=ThisOracleServer;Integrated Security=yes;" Dim queryString As String = _ "SELECT CUSTOMER_ID, NAME FROM DEMO.CUSTOMER" Using connection As New OracleConnection(connectionString) Dim command As OracleCommand = connection.CreateCommand() command.CommandText = queryString Try connection.Open() Dim dataReader As OracleDataReader = _ command.ExecuteReader() Do While dataReader.Read() Console.WriteLine(vbTab & "{0}" & vbTab & "{1}", _ dataReader(0), dataReader(1)) Loop dataReader.Close() Catch ex As Exception Console.WriteLine(ex.Message) End Try End Using End Sub End Class 7