<?xml version="1.0"  encoding="ISO-8859-1" ?> <!-- encoding="windows-1252" ?> -->
<?xml-stylesheet type="text/xsl" href="../csharp.xsl"?> 

<document>
<title>Acceso a bases de datos con ADO.NET</title>

<navigation>
 <prev>
  <ref>../language/index.xml</ref>
  <title>El lenguaje de programación C#</title>
 </prev>
 <next>
   <ref>../xml/index.xml</ref>
   <title>XML</title>
 </next>
</navigation>

<!-- Bases de datos relacionales -->

<document>
<tag>relational</tag>
<title>Bases de datos</title>

<text>
Cualquier aplicación de interés requiere el almacenamiento y posterior recuperación de los datos con los que trabaje (pedidos en aplicaciones de comercio electrónico, datos de personal para las aplicaciones de recursos humanos, datos de clientes en sistemas CRM, etc.). Los sistemas de gestión de bases de datos (DBMSs) nos permiten almacenar, visualizar y modificar datos, así como hacer copias de seguridad y mantener la integridad de los datos, proporcionando una serie de funciones que facilitan el desarrollo de nuevas aplicaciones.
</text>
<!-- 
Database needs vary with the type of application
  Transaction Processing/OLTP
  Business Intelligence/Data Warehouse/OLAP

Evolution of database technology
  File-based
  Hierarchical
  Network
  Relational (RDBMS)
  Object-oriented
  XML
-->

<text>
Desde un punto de vista intuitivo, una base de datos no es más que un fondo común de información almacenada en una computadora para que cualquier persona o programa autorizado pueda acceder a ella, independientemente de su lugar de procedencia y del uso que haga de ella. Algo más formalemente, una base de datos es un conjunto de datos comunes a un "proyecto" que se almacenan sin redundancia para ser útiles en diferentes aplicaciones.
</text>

<text>
El Sistema de Gestión de Bases de Datos (DBMS) es el software con capacidad para definir, mantener y utilizar una base de datos. Un sistema de gestión de bases de datos debe permitir definir estructuras de almacenamiento, así como acceder a los datos de forma eficiente y segura. Ejemplos: Oracle, IBM DB2, Microsoft SQL Server, Interbase...
</text>

<text>
En una base de datos, los datos se organizan independientemente de las aplicaciones que los vayan a usar (independencia lógica) y de los ficheros en los que vayan a almacenarse (independencia física). Además, los datos deben ser accesibles a los usuarios de la manera más amigable posible, generalmente mediante lenguajes de consulta como SQL o Query-by-example. Por otro lado, es esencial que no exista redundancia (esto es, los datos no deben estar duplicados) para evitar problemas de consistencia e integridad.
</text>

<document>
<title>Bases de datos relacionales</title>

<list>
<item><b>Tabla o relación</b>: Colección de registros acerca de entidades de un tipo específico (p.ej. alumnos).</item>
<item><b>Atributo, campo o columna</b>: Propiedad asociada a una entidad (p.ej. nombre, apellidos...). Cada atributo tiene un tipo asociado (p.ej. entero, cadena de caracteres...) y puede tomar el valor nulo (null).</item>
<item><b>Tupla, registro o fila</b>: Datos relativos a un objeto distinguible de otros (p.ej. un alumno concreto).</item>
</list>

<text>
Se pueden estrablecer relaciones entre las tablas de una base de datos relacional mediante el uso de claves primarias y claves externas (p.ej. cada libro tiene, al menos, un autor).
</text>

<list>
<item><b>Clave primaria</b>: Conjunto de atributos que nos permiten identificar unívocamente a una entidad dentro de un conjunto de entidades (p.ej. número de matrícula). La clave primaria garantiza la unicidad de una tupla, pues no se permite la existencia de varios registros que compartan su clave primaria.</item>
<item><b>Clave externa</b>: Conjunto de atributos que hacen referencia a otra tabla, lo que nos permite establecer relaciones lógicas entre distintas tablas. Los valores de los atributos de la clave externa han de coincidir con los valores de los atributos de una clave (usualmente la primaria) en una de las tuplas de la tabla a la que se hace referencia (integridad referencial).</item>
</list>

<image>
 <url>image/schema.gif</url>
</image>

<!--
One-to-One (1:1)
 One row in table X matches one row in table Y
 A book has at most one Library of Congress entry
One-to-Many (1:M)
 One row in table X matches 0+ rows in table Y
 A publisher publishes one or more books
Many-to-Many (M:N)
 1+ rows in table X matches 1+ rows in table Y
 An author writes one or more books; a book is written by one or more authors
 Difficult to ensure data integrity -> The remedy: Create a third table
 The third table contains the primary key of the two original tables in a composite key

Normalization
 The process of breaking large tables into multiple smaller tables
 Goal: minimize redundant data, maximize correctness
 Improves performance for updates
 Desirable in transaction-based applications
Denormalization
 The process of combining smaller tables into fewer larger tables
 Goal: improve performance
 Introduces redundant data
 Improves performance for reads
 Desirable in data warehouse applications

A JOIN is a way of combining data in multiple tables, usually by resolving primary key/foreign key relationships

A VIEW is a virtual table
 Abstracts the underlying table structures
 Abstracts a (possibly complex) query
 Provides security abstraction from table

STORED PROCEDURES
A group of SQL statements that runs within the database
 Not part of SQL standard
 Provides greater performance
 Can control access to data
 Can accept parameters
 Can return data: Output parameters, Return values, Result set

 vg: SQL Server


TRIGGERS
Like stored procedures, triggers are code that runs within a database
Not directly called by a user
Executed when a specified data modification takes place (INSERT, UPDATE or DELETE)
Enforces business rules
  FOR AFTER: trigger executes after triggering action completes
  FOR INSTEAD OF: trigger executes in place of triggering action
-->

<document>
<title>SQL</title>

<text>
Lenguaje estándar para acceder a una base de datos relacional, estandarizado por el American National Standards Institute (ANSI): SQL-92. En gran parte, los distintos DBMS utilizan todos el mismo SQL, si bien cada vendedor le ha añadido sus propias extensiones. El lenguaje SQL se divide en:
</text>

<list>
<item>DDL (Data Definition Language), utilizado para crear y modificar la estructura de la base de datos (p.ej. CREATE TABLE).</item>
<item>DML (Data Manipulation Language), empleado para manipular los datos almacenados en la base de datos (p.ej. consultas con la sentencia SELECT).</item>
<item>DCL (Data Control Language), para establecer permisos de acceso (GRANT, REVOKE, DENY) y gestionar transacciones (COMMIT y ROLLBACK).</item>
</list>

</document>
</document>

</document>


<!-- Acceso a bases de datos -->

<document>
<tag>CLIs</tag>
<title>Interfaces de acceso a bases de datos</title>

<text>
Evolución histórica de los "estándares" propuestos por Microsoft:
</text>

<list>
<item><b>ODBC (Open Database Connectivity)</b>: API estándar ampliamente utilizado, disponible para múltiples DBMSs, utiliza SQL para acceder a los datos.</item>
<item><b>DAO (Data Access Objects)</b>: Interfaz para programar con bases de datos JET/ISAM, utiliza automatización OLE y ActiveX.</item>
<item><b>RDO (Remote Data Objects)</b>: Fuertemente acoplado a ODBC, orientado al desarrollo de aplicaciones cliente/servidor.</item>
<item><b>OLE DB</b>: Construido sobre COM, permite acceder a bases de datos tanto relacionales como no relacionales (no está restringido a SQL). Se puede emplear con controladores ODBC y proporciona un interfaz a bajo nivel en C++.</item>
<item><b>ADO (ActiveX Data Objects)</b>: Ofrece un interfaz orientado a objetos y proporciona un modelo de programación para OLE DB accesible desde lenguajes distintos a C++ (p.ej. Visual Basic).</item>
</list>


<image>
 <url>image/ado.gif</url>
</image>

<text>
ADO se diseñó para su uso en arquitecturas cliente/servidor con bases de datos relacionales (no jerárquicas, como es el caso de XML). Su diseño no está demasiado bien factorizado (ya que existen muchas formas de hacer las cosas y algunos objetos acaparan demasiadas funciones) y ADO no estaba pensado para arquitecturas multicapa en entornos distribuidos.
</text>

<text>
<b>ADO .NET</b> es una colección de clases, interfaces, estructuras y tipos enumerados que permiten acceder a los datos almacenados en una base de datos desde la plataforma .NET. Si bien se puede considerar una versión mejorada de ADO, no comparte con éste su jerarquía de clases (aunque sí su funcionalidad). 
<!-- manteniendo el modelo de programación de ADO mediante la interoperabilidad de la plataforma .NET con el modelo COM. -->
</text>
<!--
These collections are organized into namespaces: System.Data, System.Data.OleDb, System.Data.SqlClient, etc.
 Well-factored design
 Highly scaleable through a robust disconnected model
-->

<text>
ADO .NET combina las capas ADO y OLE DB en una única capa de proveedores (<i>managed providers</i>). Cada proveedor contiene un conjunto de clases que implementan interfaces comunes para permitir el acceso uniforme a distintas fuentes de datos. Ejemplos: ADO Managed Provider (da acceso a cualquier fuente de datos OLE DB), SQL Server Managed Provider (específico para el DBMS de Microsoft), Exchange Managed Provider (datos almacenados con Microsoft Exchange)...
</text>

<image>
 <url>image/adonet.gif</url>
</image>

<!--
Feature	
ADO
ADO.NET

 Memory-resident Data Representation
 Uses RecordSet, which can contain one table
 Uses DataSet, which can contain one or more tables represented by DataTables

 Relationship Between Multiple Tables	
 Require the JOIN query	
 Supports the DataRelation object

 Data Visitation	
 Scans RecordSet rows sequentially	
 Uses a navigation paradigm for non-sequential access

 Disconnected Access	
 Provided by RecordSet but typically supports connected access	
 Communicates with standardized calls to the DataAdapter

 Programmability	
 Uses Connection object to transmit commands	
 Uses strongly typed programming characteristics of XML

 Sharing Disconnected Data Between Tiers or Components	
 Uses COM marshalling to transmit disconnected Recordset	
 Transmits a DataSet with an XML file

 Transmitting Data Through Firewalls	
 Problematic because firewalls are typically configured to prevent system-level requests	
 Supported, DataSet object use XML, which can pass through firewalls
 
 Scalability	
 Database locks and active database connections for long durations	
 Disconnected access to database data without retaining database locks
-->

<text>
ADO .NET usa XML. De hecho, los conjuntos de datos se almacenan internamente en XML, en vez de almacenarse en binario como sucedía en ADO. Al estar los datos almacenados en XML, se simplifica el acceso a los datos a través de HTTP (algo que ocasiona problemas en ADO si los datos tienen que pasar cortafuegos).  Por otro lado, se simplifica la comunicación entre aplicaciones al ser XML un formato estándar (p.ej. comunicación con applets Java).
</text>

<text>
Con ADO .NET se puede acceder a los datos de dos formas distintas:
</text>

<list>
<item>Acceso conectado: Acceso sólo de lectura con cursores unidireccionales ("firehose cursors"). La aplicación realiza una consulta y lee los datos conforme los va procesando con la ayuda de un objeto <type>DataReader</type>.</item>
<item>Acceso desconectado: La aplicación ejecuta la consulta y almacena los resultados de la misma para procesarlos después accediendo a un objeto de tipo <type>DataSet</type>. De esta forma, se minimiza el tiempo que permanece abierta la conexión con la base de datos.</item>
</list>

<text>
Al proporcionar conjuntos de datos de forma desconectada, se utilizan mejor los recursos de los servidores y se pueden construir sisyemas más escalables que con ADO (que mantenía abierta la conexión con la base de datos la mayor parte del tiempo). Este enfoque resulta más adecuado en sistemas distribuidos como Internet.
</text>

</document>


<!-- Arquitectura ADO.NET -->

<document>
<tag>architecture</tag>
<title>Arquitectura ADO.NET</title>

<text>
El funcionamiento de ADO.NET se basa esencialmente en utilizar los siguientes componentes:
</text>

<list>
<item><b>Data Provider</b> (proveedor de datos): Proporciona un acceso uniforme a conjuntos de datos (bases de datos relacionales o información ID3 de ficheros MP3). Su papel el similar al de un controlador ODBC o JDBC.</item>
<item><b>DataSet</b>: El componente más importante, puede almacenar datos provenientes de múltiples consultas (esto es, múltiples tablas).</item>
<item><b>DataAdapter</b>: Sirve de enlace entre el contenedor de conjuntos de datos (DataSet) y la base de datos (Data Provider).</item>
</list>

<text>
Los componentes anteriores se completan con <b>DataReader</b> (para realizae eficientemente lecturas de grandes cantidades de datos que no caben en memoria), <b>DataRelation</b> (la forma de establecer una reunión entre dos tablas), <b>Connection</b> (utilizada por DataAdapter para conectarse a la base de datos) y <b>Command</b> (que permite especificar las órdenes, generalmente en SQL, que nos permiten consultar y modificar el contenido de la base de datos: select, insert, delete y update).
</text>

<text>
Un proveedor de datos debe proporcionar una implementación de Connection, Command, DataAdapter y DataReader.
</text>

<text>
El modo de funcionamiento típico de ADO.NET es el siguiente:
</text>

<list>
<item>Se crean un objeto Connection especificando la cadena de conexión.</item>
<item>Se crea un DataAdapter.</item>
<item>Se crea un objeto Command asociado al DataAdapter, con la conexión adecuada y la sentencia SQL que haya de ejecutarse.</item>
<item>Se crea un DataSet donde almacenar los datos.</item>
<item>Se abre la conexión.</item>
<item>Se rellena el DataSet con datos a través del DataAdapter.</item>
<item>Se cierra la conexión.</item>
<item>Se trabaja con los datos almacenados en el DataSet.</item>
</list>

<text>
Como los conjuntos de datos se almacenan en memoria y trabaja con ellos de forma desconectada, cuando hagamos cambios sobre ellos (inserciones, borrados o actualizaciones) debemos actualizar el contenido de la base de datos llamando al método Update del DataAdapter y, posteriormente, confirmar los cambios realizados en el DataSet (con AcceptChanges) o deshacerlos (con RejectChanges).
</text>

</document>

<!-- Clases ADO.NET -->


<document>
<tag>ADO.NET</tag>
<title>Clases ADO.NET</title>

<text>
ADO .NET define una serie de interfaces que proporcionan la funcionalidad básica común a las distintas fuentes de datos accesibles a través de ADO .NET. La implementación de estos interfaces por parte de cada proveedor proporciona acceso a un tipo concreto de fuentes de datos y puede incluir propiedades y métodos adicionales.
</text>

<!--
System.Data Namespace

Contains the core classes of the ADO.NET architecture
Disconnected DataSet is central
Supports all types of applications
 Internet based: ASP.NET & XML
 Windows forms based

Contains classes used by or derived from managed providers
IDbConnection, IDbCommand, IDbDataReader
-->

<document>
<title>Interfaz IDbConnection</title>

<text>
Establece una sesión con una fuente de datos. Permite abrir y cerrar conexiones, así como comenzar transacciones (que se finalizan con los métodos <type>Commit</type> y <type>Rollback</type> de <type>IDbTransaction</type>. Las clases <type>SqlDbConnection</type> y <type>OleDbConnection</type> implementan el interfaz de <type>IDbConnection</type>.
</text>
<!--
Used in conjunction with IDbCommand and IDataAdapter objects
Additional properties, methods and collections depend on the provider
-->
</document>


<document>
<title>Interfaz IDbCommand</title>

<text>
Representa una sentencia que se envía a una fuente de datos (usualmente en SQL, aunque no necesariemente). Las clases <type>SqlDbCommand</type> y <type>OleDbCommand</type> implementan el interfaz de <type>IDbCommand</type>.
</text>

<text>
<type>IDbCommand</type> nos permite definir la sentencia que se ha de ejecutar, ejecutar la sentencia, pasarle parámetros y prepararla (crear una versión "compilada" de la misma para que su ejecución sea más eficiente cuando ha de repetirse varias veces). El método <type>ExecuteReader</type> devuelve un conjunto de tuplas (véase el interfaz <type>IDataReader</type>), mientras que <type>ExecuteScalar</type> devuelve un valor único (p.ej. ejecución de procedimientos almacenados) y <type>ExecuteNonQuery</type> no devuelve nada (p.ej. borrados y actualizaciones).
</text>


<example>
<code>
string connectionString = "Persist Security Info=False;" +
                          "User ID=sa;Initial Catalog=MYDB;" +
                          "Data Source=MYSERVER";

SqlConnection connection = new SqlConnection(connectionString);

// Ejecución de sentencias SQL
// ---------------------------

string sqlInsert = "INSERT INTO Department(DepartmentName) VALUES (@DepartmentName)";

SqlCommand insertCommand = new SqlCommand(sqlInsert, connection);


SqlParameter  param = insertCommand.Parameters.Add ( 
                        new SqlParameter("@DepartmentName", SqlDbType.VarChar, 100));

param.Value = ...

connection.Open();

insertCommand.ExecuteNonQuery();

connection.Close();


// Llamadas a procedimientos almacenados
// -------------------------------------

// C#

string spName = "CREATE_DEPARTMENT"

SqlCommand command = new SqlCommand(spName, connection);

command.CommandType = CommandType.StoredProcedure;


SqlParameter in = command.Parameters.Add ( 
                    new SqlParameter("@DepartmentName", SqlDbType.VarChar, 100));
in.Value = ...

SqlParameter out = command.Parameters.Add ( 
                    new SqlParameter("RETVAL", SqlDbType.Int));
out.Direction = ParameterDirection.ReturnValue;

connection.Open();

insertCommand.ExecuteNonQuery();

int newID = command.Parameters("RETVAL").Value;

connection.Close();



// SQL Server
// ----------

CREATE TABLE [dbo].[Department] (
	[DepartmentID] [int] IDENTITY (1, 1) NOT NULL ,
	[DepartmentName] [varchar] (100),
	[CreationDate] [datetime] NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Department] WITH NOCHECK ADD 
	CONSTRAINT [PK_Department] PRIMARY KEY  CLUSTERED 
	(
		[DepartmentID]
	)  ON [PRIMARY] 
GO


CREATE PROCEDURE dbo.CreateDepartment
@DepartmentName varchar(100), 
AS
	INSERT INTO Department (DepartmentName, CreationDate)
	VALUES (@DepartmentName, GetDate())
	RETURN scope_identity()
GO

</code>
</example>


</document>


<document>
<title>Interfaz IDataReader</title>

<text>
Proporciona acceso secuencial de sólo lectura a una fuente de datos. Las clases <type>SqlDataReader</type> y <type>OleDbDataReader</type> implementan el interfaz de <type>IDataReader</type>. Al utilizar un objeto <type>IDataReader</type>, las operaciones sobre la conexión <type>IDbConnection</type> quedan deshabilitadas hasta que se cierre el objeto <type>IDataReader</type>.
</text>

<example>
<code>
string connectionString = "Provider=SQLOLEDB.1;" +
                          "User ID=sa;Initial Catalog=Northwind;" +
                          "Data Source=MYSERVER";

OleDbConnection connection = new OleDbConnection(connectionString);


string sqlQuery = "SELECT CompanyName FROM Customers";

OleDbCommand myCommand = new OleDbCommand(sqlQuery, connection);

connection.Open();

OleDbDataReader myReader = myCommand.ExecuteReader();

while (myReader.Read()) {
   Console.WriteLine(myReader.GetString(0));
}

myReader.Close();

connection.Close();
</code>
</example>

</document>


<document>
<title>Clase DataSet</title>

<text>
Un objeto <type>DataSet</type> encapsula un conjunto de tablas independientemente de su procedencia y mantiene las relaciones existentes entre las tablas. El contenido de un <type>DataSet</type> puede serializarse en formato XML. Además, se permite la modificación dinámica de los datos y metadatos del conjunto de datos representado por el objeto <type>DataSet</type>. 
</text>


<text>
El interfaz <type>IDataAdapter</type> implementado <type>OleDbDataAdapter</type> y <type>SqlDataAdapter</type> se utiliza para construir el conjunto de datos y actualizarlo cuando sea necesario. Los conjuntos de datos con los que se trabaja de esta forma utilizan un enfoque asíncrono en el que no se mantiene abierta la conexión con la base de datos a la que se está accediendo. Al trabajar con conjuntos de datos de esta forma, se dispone de un superconjunto de los comandos que se permiten cuando se emplea el interfaz <type>IDataReader</type>. De hecho se pueden realizar operaciones de consulta (<type>select</type>), inserción (<type>insert</type>), actualización (<type>update</type>) y borrado (<type>delete</type>).
</text>

<example>
<code>
string connectionString = "Persist Security Info=False;" +
                          "User ID=sa;Initial Catalog=Northwind;" +
                          "Data Source=MYSERVER";

SqlConnection connection = new SqlConnection(connectionString);

SqlDataAdapter myDataAdapter = new SqlDataAdapter();

DataSet myDataSet = new DataSet();


string sqlQuery = "SELECT * FROM Customers";

myDataAdapter.SelectCommand = new SqlCommand(sqlQuery, connection);


connection.Open();

myDataAdapter.Fill(myDataSet);

conn.Close();
</code>
</example>




<image>
 <title>Visión simplificada del contenido de DataSet</title>
 <url>image/dataset.gif</url>
</image>


<document>
<title>Clase DataTable</title>
<text>
Representa una tabla en memoria (Columns &amp; Rows) cuyo esquema viene definido por su colección de columnas <type>Columns</type>. La integridad de los datos se conserva gracias a objetos que representan restricciones (<type>Constraint</type>) y dispone de eventos públicos que se producen al realizar operaciones sobre la tabla (p.ej. modificación o eliminación de filas).
</text>
</document>

<document>
<title>Clase DataColumn</title>
<text>
Define el tipo de una columna de una tabla (vía su propiedad <type>DataType</type>) e incluye las restricciones (<type>Constraints</type>) y las relaciones (<type>Relations</type>) que afectan a la columna. Además, posee propiedades útiles como <type>AllowNull</type>, <type>Unique</type> o <type>ReadOnly</type>.
</text>
</document>


<document>
<title>Clase DataRow</title>
<text>
Representa los datos de una tabla (almacenados en la colección <type>Rows</type> de un objeto <type>DataTable</type>), de acuerdo con el esquema definido por las columnas de la tabla (<type>Columns</type>). Además, incluye propiedades para determinar el estado de una fila/tupla particular (p.ej. nuevo, cambiado, borrado, etc.).
</text>
<!-- 
All additions/modifications “committed” with AcceptChanges method of DataTable
-->
</document>

<document>
<title>Clase DataRelation</title>
<text>
Relaciona dos <type>DataTables</type> vía <type>DataColumns</type> y sirve para mantener restricciones de integridad referencial. Obviamente, el tipo de las columnas relacionadas ha de ser idéntico. Para acceder a los datos relacionados con un registro concreto basta con emplear el método <type>GetChildRecords</type> de la tupla correspondiente (<type>DataRow</type>). 
</text>
<!--
Updates can be cascaded to child DataTables
Modifications that invalidate the relation are disallowed
-->
</document>

<example>
<title>Creación de una base de datos</title>
<code>
// Creación de las tablas, columnas y claves primarias/externas

DataTable authors = new DataTable("Author");
DataTable books = new DataTable("Book");

DataColumn id = authors.Columns.Add("ID", typeof(Int32));
DataColumn name = new authors.Columns.Add("Name",typeof(String));
authors.PrimaryKey = new DataColumn[] {id};
id.AutoIncrement = true;

DataColumn isbn  = books.Columns.Add("ISBN", typeof(String));
DataColumn title  = books.Columns.Add("Title", typeof(String));
DataColumn authid = books.Columns.Add(“AuthID”,typeof(Int32));
books.PrimaryKey = new DataColumn[] {isbn};

DataColumn[] foreignkey = new DataColumn[] {authid};
DataRelation bookauth = new DataRelation("BookAuthors",                
				authors.PrimaryKey, foreignkey);

// Creación del DataSet: tablas y relaciones

DataSet dataset = new DataSet();
dataset.DataSetName = "BookAuthors";
dataset.Tables.Add (authors);
dataset.Tables.Add (books);

dataset.Relations.Add (bookauth);

// Inserción de datos

DataRow shkspr = authors.NewRow();
shkspr["Name"] = "William Shakespeare";
authors.Rows.Add(shkspr);

DataRow row = books.NewRow();
row["AuthID"] = shkspr["ID"];
row["ISBN"] = "1000-XYZ";
row["Title"] = "MacBeth";
books.Rows.Add(row);

// Commit

dataset.AcceptChanges();
</code>
</example>

<!--

Typed DataSets
 Derived from base DataSet class
 Uses XML schema to generate new class
 Tables, columns, etc. compiled into new class
 vg:  ds.Customers.FirstName

Untyped DataSet
 No built-in schema
 Tables, columns, etc. exposed only as collections
 vg: ds.Tables[“Customers”].Rows[0][“FirstName”]
-->

</document>

</document>

<!--
PROVEEDORES ADO.NET

System.Data.OleDb Namespace

Managed provider for use with OLEDB providers
  SQLOLEDB (SQL Server) – use System.Data.SQL
  MSDAORA (Oracle)
  JOLT (Jet)
  OLEDB for ODBC providers
OleDbConnection, OleDbCommand and OleDbDataReader classes
Classes for error handling
Classes for connection pooling


System.Data.SqlClient Namespace

Managed provider native to SQL Server
Built on TDS (Tabular Data Stream) for high performance in SQL Server
SqlConnection, SqlCommand and SqlDataReader classes
Classes for 
Error handling
Connection pooling (implicitly enabled by default )
System.Data.SqlTypes provides classes for native SQL Server data types

-->

<!--

ERRORES Y EXCEPCIONES

Error class
  Contains information on an error or warning returned by data source
  Created and managed by Errors class
Errors class
  Contains all errors generated by an adapter
  Created by Exception class
Exception class
  Created whenever an unhandled error occurs
  Always contains at least one Error instance

<code>
try {
  DataTable myTable = new DataTable();
  myTable.Columns.Add(“myCol”);
  myTable.Columns.Add(“myCol”);
  //whoops!
}
catch (DataException myException) {
  Console.WriteLine ("Message: " + myException.Message + "\n" +
      "Source: " + myException.Source + "\n" +
      “Stack Trace: " + myException.StackTrace + "\n");
} 
</code>
-->

<!--
DATA BINDING

Key component of Web Forms framework

Flexible and easy to use
  Bind a control’s property to information in any type of data store
  Provides control over how data moves back and forth
  Simple controls for displaying a single value
  Complex controls for displaying a data structure

  <asp:Label runat=server Text='<%# CustList(0).FirstName %>'/>
-->

<document>
<tag>transactions</tag>
<title>Transacciones en ADO.NET</title>

<!--
  Atomic: All statements execute successfully or all fail
  Consistent: Must leave the data in a consistent state when completed
  Isolated: Cannot see the modifications made by concurrent transactions
  Durable: Must be permanent when complete, even in the event of system failure
-->

<text>
Las transacciones son conjuntos de operaciones que han de efectuarse de forma atómica. La acidez de una transacción hace referencia a sus propiedades deseables: atomicidad, consistencia, aislamiento y durabilidad (<i>ACID = Atomicity, Consistency, Isolation, Durability</i>).
</text>

<text>
En ADO.NET, los límites de las transacciones se indican manualmente. Los objetos de la clase <type>Connection</type> tienen un método <type>BeginTransaction</type> que devuelve una transacción (objeto de tipo <type>Transaction</type>). La transacción finaliza cuando se llama al método <type>Commit</type> o <type>Rollback</type> del objeto <type>Transaction</type> devuelto por <type>BeginTransaction</type>.
</text>


<!--
Concurrencia en bases de datos:

Isolation levels
  Read Uncommitted
  Read Committed
  Repeatable Read
  Serializable
  Tradeoffs (concurrency vs. data integrity)

Locking
  Ensures transactional integrity/database consistency
  Prevents users from seeing "phantom" data
  Can result in deadlocks
-->
</document>

<document>
<tag>data-binding</tag>
<title>Data Binding</title>

<text>
Éste es el nombre por el que se conoce el mecanismo que nos permite asociar el contenido de un conjunto de datos a los controles de la interfaz de nuestra aplicación, algo que facilitan los entornos de programación visual (como es el caso del Visual Studio .NET).
</text>

<example>
<title>Data Binding en Visual Studio .NET</title>

Se puede optar por asistentes del tipo de <b>DataForm wizard</b>... o, cuando éstos no nos ofrecen la funcionalidad suficiente para nuestras aplicaciones, podemos programarlo nosotros mismos (algo que no es difícil y nos da bastante más control sobre nuestra aplicación):

<list>
<item>Se crean los objetos ADO.NET necesarios (Connection, DataSet, Command y DataAdapter).</item>
<item>Se enlazan los controles de la interfaz con las columnas del DataSet, lo que se consigue añadiendo un objeto <type>System.Windows.Forms.Binding</type> a la propiedad <type>DataBindings</type> del control. Los objetos de tipo <type>Binding</type> nos permiten enlazar una propiedad de un control a una columna de un <type>DataSet</type>.</item>
<item>Se implementa la forma de recorrer los registros, haciendo uso del objeto <type>BindingContext</type> asociado al formulario (cuyas propiedades <type>Position</type> y <type>Count</type> nos permiten movernos por el conjunto de datos).</item>
<item>Se implementan las operaciones sobre la base de datos (con los comandos asociados al <type>DataAdapter</type>.</item>
</list>

</example>

<text>
NOTA: Cuando los conjuntos de datos sean grandes, es recomendable utilizar ADO.NET con paginación para no tener que leer todos los datos de la base de datos (véase "ADO.NET data paging"). En situaciones como ésa, también suele ser recomendable añadir capacidades de búsqueda a nuestras aplicaciones (véase el método <type>Find</type>).
</text>


</document>
<!--
RECURSOS

Introducing ADO+
http://msdn.microsoft.com/msdnmag/issues/1100/adoplus/adoplus.asp
ADO.NET
http://msdn.microsoft.com/library/default.asp?URL=/library/dotnet/cpguide/cpconaccessingdata.htm 
ADO+ Guides the Evolution of the Data Species
http://msdn.microsoft.com/library/techart/adoplus.htm
ADO.NET for the ADO Programmer
http://msdn.microsoft.com/library/techart/adonetdev.htm
ADO Rocks and Rolls in .NET Applications
http://msdn.microsoft.com/library/welcome/dsmsdn/data02222001.htm
Meditating on OLE DB and .NET
http://msdn.microsoft.com/library/welcome/dsmsdn/data03222001.htm
Reading Data Reader Secrets
http://msdn.microsoft.com/library/welcome/dsmsdn/data04122001.htm
Database-like Data Containers
http://msdn.microsoft.com/library/default.asp?URL=/library/welcome/dsmsdn/data04122001.htm
ADO
http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/dasdk/ados4piv.htm
Universal Data Access
http://www.microsoft.com/data/
SQL Server
http://www.microsoft.com/sql/default.asp
-->

</document>

