Capitulo 1: clases desconectadas de ADO.NET (Parte 1)

Lección 1: Trabajando con las clases DataTable y DataSet
La jerarquía de ADO.NET se puede dividir en dos categorías: conectadas y desconectadas.
En este grafico se muestran las primeras clases ADO.NET, luego se fueron implementando nuevas funcionalidades y una mejor performance.
image
Estas clases están implementadas en el ensamblado System.Data.dll del .NET Framework y se encuentran en el namespace System.Data.
 

La clase DataTable

Un DataTable representa una tabla de datos en memoria, una tabla en cache de filas, columnas, y limitaciones (Constrains). Se usa para trabajar con el acceso a datos sin conexión.
Se crea una instancia DataTable, y después agregamos un DataColumn que define el tipo de datos que va a contener y luego se insertan DataRows que contengan la información:
Creo un DataTable llamada “Cars
---------------------------------VB---------------------------------
'asi creo el Datatable 
        Dim cars As New DataTable("Cars")
---------------------------------CS---------------------------------
//asi creo el Datatable 
            var car = new DataTable("Cars");
--------------------------------------------------------------------
Se puede usar la propiedad TableName para acceder a los datos de la tabla cuando se encuentra en una colección de DataTables. Esta no es muy útil hasta que le creamos su esquema, con DataColums y le agregamos limitaciones. Las limitaciones sirven para mantener la integridad de los datos.
Ejemplo de cómo agregar dataColums y setear sus propiedades:
---------------------------------VB---------------------------------
   'creo el Datacolum y le seteo sus propiedades
        Dim vin As New DataColumn("Vin")
        vin.DataType = GetType(String) 'por defecto es string 
        vin.MaxLength = 23 'por defecto es -1
        vin.Unique = True ' si es clave principal
        vin.AllowDBNull = False 'por defecto es True
        vin.Caption = "VIN" 'titulo de la columna
        cars.Columns.Add(vin) ' se la agrego al datatable
---------------------------------CS---------------------------------
  //creo el Datacolum y le seteo sus propiedades 
        var vin= new DataColumn();
        vin.DataType = typeof(string);// por defecto string
        vin.MaxLength = 23; // por defecto -1
        vin.Unique = true;  // clave principal por defecto false
        vin.AllowDBNull= false; // por defecto es true
        vin.Caption="VIN"; // el titulo de 
        car.Columns.Add(vin); //agrego la columna al datatable
--------------------------------------------------------------------

El constructor del datacomlum tiene varias sobrecargas:

NombreDescripción
DataColumn ()Inicializa una nueva instancia de la clase DataColumn de tipo string.
DataColumn (String)Inicializa una nueva instancia de la clase DataColumn, de tipo string, utilizando el nombre de columna especificado.
DataColumn (String, Type)Inicializa una nueva instancia de la clase DataColumn con el nombre de columna y el tipo de datos especificados.
DataColumn (String, Type, String)Inicializa una nueva instancia de la clase DataColumn con el nombre, el tipo de datos y la expresión especificados.
DataColumn (String, Type, String, MappingType)Inicializa una nueva instancia de la clase DataColumn con el nombre, el tipo de datos, la expresión y un valor que determina si la columna es un atributo; todos ellos especificados.

Creo una columna primary Key, esta debe ser única, para identificar la fila.
-------------------------------VB-----------------------------------
cars.PrimaryKey = New DataColumn() {vin}'la columna vin como clave primaria
-------------------------------CS-----------------------------------
car.PrimaryKey = new DataColumn[] { vin };// vin es clabe primaria
--------------------------------------------------------------------

Para utilizar numeración automatica en una columna que es primary key, se debe colocar true en la propiedad AutoIncrement, para definir en que numero se desea comenzar se coloca el valor en la propiedad AutoIncrementSeed  y AutoIncrementStep para setear el valor que desea sumar cada vez que se agrega una nueva fila.

Los valores de incremento automático que se generan en la aplicación nunca se envían a la base de datos debido a que la columna de incremento automático en la tabla de base de datos proporcionará un valor cuando la nueva fila se agrega.
Después de cada nueva fila se agrega,se genera un nuevo número de incremento automático, y luego su aplicación se consulta la base de datos para obtener el número de nueva creación.
La solicitud actualizara el número de clave principal a los valores que venían de la
base de datos.

Muchas veces, al agregar nuevas filas  y la base ya contiene valores se produce una excepción, porque el id ya se encuentra en la tabla de datos, para resolver ese problema se establece AutoIncrementSeed a -1 y AutoIncrementStep a -1. Esto hará que los números negativos que se generen, no entren en conflicto con los valores procedentes de la base de datos (porque la base de datos no genera los números negativos y usa los creados en la base).

Creando DataRows para almacenar datos

Después de que el objeto DataTable se crea y contiene DataColumns, se puede rellenar agregando DataRows. Un  DataRow sólo se puede crear en el contexto de un DataTable  debido a la fila deben ajustarse a las constrains de las columnas de este.
 

Agregando datos a la DataTable

Un DataTable posee una propiedad “DataRowCollection” que es laque contiene a sus DataRows. Hay varias maneras de insertar datos en esta colección.

NombreDescripción
DataRowCollection.Add (DataRow)Agrega el DataRow especificado al objeto DataRowCollection.
DataRowCollection.Add (Object[])Crea una fila mediante los valores especificados, que deben coincidir con el número exacto de DataColumns que la tabla de datos tiene y la agrega a DataRowCollection.

Para importar los DataRow que se han modificado, puede utilizar el método ImportDataRow, que preservará su estado original y todos los ajustes.
Para actualizar los objetos existentes o cargar DataRows nuevos se usan los métodos Load (
LoadDataRow: acepta un array de objetos, y LoadOption una enumeración de valores), estos requieren tener la propiedad PrimaryKey del DataTable seteada para ubicar las filas que se actualizan:

NombreDescripción
LoadDataRow(Object(), Boolean)Busca y actualiza una fila específica. Si no encuentra ninguna fila coincidente, se crea una nueva con los valores dados.
LoadDataRow(Object(), LoadOption)Busca y actualiza una fila específica.
loadOption se utiliza para determinar cómo se aplican los valores de la matriz a los valores correspondientes en una fila existente.


--------------------------------VB----------------------------------
Dim newCar As DataRow = cars.NewRow() 'creo un datarow
 newCar("Vin") = "123456789ABCD" 'seteo los valores
 newCar("Make") = "Ford"
 newCar("Year") = 2002
 cars.Rows.Add(newCar) 'lo agrego 
 cars.Rows.Add("987654321XYZ", "Buick", 2001)'creo el datarow pasando valores
 cars.LoadDataRow(New Object() {"987654321XYZ", "Jeep", 2002}, 
 LoadOption.OverwriteChanges)'cargo un DataRow, y reemplazo el contenido 
                             'si existe el mismo vin (PK)
---------------------------------CS---------------------------------
DataRow newCar = cars.NewRow(); //creo un DataRow
newCar["Vin"] = "123456789ABCD";// le seteo los valores
newCar["Make"] = "Ford";
newCar["Year"] = 2002;
car.Rows.Add(newCar); //lo agrego
car.Rows.Add("987654321XYZ", "Buick", 2001);
//agrego un DataRow solo seteando los valores 
//cargo el DataRow, reemplazando el contenido if la PK existe
car.LoadDataRow(new object[] { "987654321XYZ", "Jeep", 2002 },
LoadOption.OverwriteChanges);
--------------------------------------------------------------------

Viendo el estado del DataRow mediante DataRowState

Los estados se pueden ver y filtrar en cualquier momento mediante su propiedad RowState, que devuelve un valor de la enumeración DataRowState.

NombreDescripción
DetachedSe ha creado la fila, pero no forma parte de ningún DataRowCollection. DataRow se encuentra en este estado inmediatamente después de haber sido creado y antes de que se agregue a una colección, o bien si se ha quitado de una colección.
UnchangedLa fila no ha cambiado desde que se llamó a AcceptChanges por última vez.
Added
La fila se ha agregado a DataRowCollection y no se ha llamado a AcceptChanges.
DeletedLa fila se ha eliminado mediante el método Delete del DataRow.
ModifiedLa fila se ha modificado y no se ha llamado a AcceptChanges.

Ejemplo de los estados de un DataRow:image
Compatible con XNA Framework

Manejando múltiples copias de datos usando DataRowVersion


El DataTable puede tener hasta tres versiones de los datos de fila de datos: Original, Current,
y Proposed.
Cuando cambian las versiones:
  • Después de llamar al método BeginEdit del  DataRow, si cambia el valor, los valores Current y Proposed pasan a estar disponibles.
  • Después de llamar al método CancelEdit del DataRow, se elimina el valor Proposed.
  • Después de llamar al método EndEdit del DataRow, el valor Proposed se convierte en el valor Current.
  • Después de llamar al método AcceptChanges del DataRow y/o DataTable, el valor Original se vuelve idéntico al valor Current.
  • Después de llamar a RejectChanges del DataRow, se descarta el valor Proposed y la versión se convierte en Current.
Utilizando el método HasVersion del DataRow, se puede comprobar la existencia del versionada de la fila de datos antes de intentar recuperarlo.

Ejemplo de cómo recuperar una cadena, utilizando RowState y DataRowVersion:

--------------------------------VB----------------------------------
Private Function GetDataRowInfo(ByVal row As DataRow, ByVal columnName As String) As String
     Dim retVal As String = String.Format("RowState: {0}" + vbCrLf) 
     'vbCrLf = final de linea
     Dim versionString As String
     For Each versionString In [Enum].GetNames(GetType(DataRowVersion))
         Dim version As DataRowVersion = _
         CType([Enum].Parse(GetType(DataRowVersion), versionString),_
               DataRowVersion)
         If (row.HasVersion(version)) Then
             retVal += String.Format( _
             "Version: {0} Value: {1}" + vbCrLf, _
             version, row(columnName, version))
         Else
             retVal += String.Format( _
             "Version: {0} does not exist." + vbCrLf, _
             version)
         End If
    Next 'cierra el foreach 
        Return retVal
    End Function 
--------------------------------CS----------------------------------

 private string GetDataRowInfo(DataRow row, string columnName)
 {
    string retVal=string.Format("RowState: {0} \r\n",row.RowState);
    foreach (string versionString in Enum.GetNames(typeof(DataRowVersion)))
    {
        DataRowVersion version = (DataRowVersion)Enum.Parse(typeof(DataRowVersion),versionString);
        if (row.HasVersion(version))
        {
           retVal += string.Format("Version: {0} Value: {1} \r\n",
           version, row[columnName, version]);
        }
        else
        {
           retVal += string.Format("Version: {0} does not exist.\r\n",version);
        }
     }
     return retVal;
 }
--------------------------------------------------------------------


Utilizando SetAdded y SetModified para cambiar el RowState
DataRow contiene los métodos y SetAdded SetModified, que permiten forzar un estado Added o Modified. Estos métodos pueden ser ejecutados sólo en los DataRow cuyo estado no ha cambiado sino se produce la excepción llamada InvalidOperationException.
Si se ejecuta el método SetAdded  el DataRow descarta su versión original fila de datos .

Si se ejecuta el método  SetModified, la propiedad RowState del DataRow se cambia a modified sin necesidad de modificar la versión de filas de datos original o current.

Eliminar un DataRow

DataRow contiene un método de eliminación con el que puede establecer el estado de fila de la fila de datos que desea borrar.Cuando el DataRow es borrado, las versiones de los datos actuales y propuestos fila se descartan, pero sigue estando la versión original de los datos .

El DataRow no tiene un método de Undelete. Sin embargo, en algunas situaciones, puede utilizar el método RejectChanges para hacer retroceder a un estado anterior, cuando la fila eliminada todavía estaba allí (copia la versión  original a la versión actual).

Copiando y clonando un DataTable

Para crear una copia completa de una tabla de datos, se puede usar el método Copy, que copia el esquema del DataTable y sus datos.
--------------------------------VB----------------------------------
'copia el dataTable y sus datos
        Dim copy As DataTable = cars.Copy()
--------------------------------CS----------------------------------
//copia el dataTable y sus datos
        DataTable copy = car.Copy();
--------------------------------------------------------------------

Para crear solo el esquema:
--------------------------------VB----------------------------------
'copia el dataTable , no los datos
        Dim clone As DataTable = cars.Clone()
--------------------------------CS----------------------------------
//copia el dataTable y no sus datos
        DataTable clone = car.Clone();
--------------------------------------------------------------------

Importar DataRows a un DataTable

Después de clonar un  dataTable, puede ser necesario copiar algunos DataRows de una tabla de datos a otra. Un DataTable contiene el método ImportRow,que se puede usar para copiar una fila  de una tabla de datos que tiene el mismo esquema, siempre y cuando no exista una fila con la misma clave principal, sino lanza ConstraintException.
--------------------------------VB----------------------------------
'copia el dataTable , no los datos
    Dim clone As DataTable = cars.Clone()
'importa e incluye todas las verciones de la fila
    clone.ImportRow(cars.Rows(0))
--------------------------------CS----------------------------------
//copia el dataTable y no sus datos
    DataTable clone = car.Clone();
 //importa e incluye todas las verciones de la fila
    clone.ImportRow(car.Rows[0]);
--------------------------------------------------------------------

Utilizando DataView como una ventana en un DataTable

Una DataTable puede tener muchos objetos DataView asignados, de esta forma los datos se pueden ver de muchas maneras sin necesidad de que se vuelva a leer desde la base de datos. Las propiedades Sort, RowFilter, y RowStateFilter del DataView se pueden combinar según sea necesario. también se puede utilizar AllowDelete, AllowEdit, y las propiedades AllowNew para permitir la entrada del usuario.

Internamente, un DataView es un índice que permite ordenar los datos (propiedad Sort) en un orden determinado, y puede proporcionar un filtro para las entradas del índice.
--------------------------------VB----------------------------------
‘creo un DataView y ordenos sus columnas 
 Dim view As New DataView(cars)
 view.Sort = "Make ASC, Year DESC"
--------------------------------CS----------------------------------
 //creo un DataView y ordenos sus columnas   
 DataView view = new DataView(cars);
 view.Sort = "Make ASC, Year DESC";

--------------------------------------------------------------------

Reduciendo la búsqueda mediante las Propiedades  RowFilter y RowStateFilter
La propiedad RowFilter establece una cláusula WHERE de SQL sin la palabra "WHERE". Ejemplo de un filtro en la columna Make a partir de la letra B y en la columna Year para los nuevos automóviles que en 2003:
--------------------------------VB----------------------------------
 view.RowFilter = "Make like 'B%' and Year > 2003"
--------------------------------CS----------------------------------
 view.RowFilter = "Make like 'B%' and Year > 2003";
--------------------------------------------------------------------

La propiedad RowStateFilter proporciona un filtro que se aplica en la propiedad propiedad RowState o en cada fila de datos. Este filtro ofrece un método fácil de recuperar versiones específicas de las filas dentro de la tabla de datos. La propiedad RowStateFilter requiere el uso de la enumeración DataViewRowState.

NombreDescripción
AddedFila nueva.
CurrentRowsFilas actuales, incluidas las filas sin modificar, las nuevas y las modificadas
DeletedFila eliminada.
ModifiedCurrentVersión actual, que es una versión modificada de los datos originales
ModifiedOriginal
Versión original (aunque se haya modificado y esté disponible como ModifiedCurrent). 
NoneNinguno.
OriginalRowsCompatible con .NET Compact Framework
Filas originales, incluidas las filas sin modificar y las eliminadas.
UnchangedFila sin modificar.

Ejemplo de filtro de RowState  para recuperar sólo los DataRow que tienen un estado Deleted.
--------------------------------VB----------------------------------
 view.RowStateFilter = DataViewRowState.Deleted
--------------------------------CS----------------------------------
 view.RowStateFilter = DataViewRowState.Deleted;
--------------------------------------------------------------------
Compatible con .NET Compact Framework

Compatible con .NET Compact FrameworkEnumerar DataViews

El procedimiento para recorrer dataViews es similar a la de la enumeración de DataTables
Ejemplo para recorrer las filas de la vista, recuperando la información de las columnas y mostrando los datos en un textBox:
--------------------------------VB----------------------------------
 Public Sub EnumerateView(ByVal view As DataView)
    Dim buffer As New System.Text.StringBuilder()
    For Each dc As DataColumn In view.Table.Columns
       buffer.AppendFormat("{0,15} ", dc.ColumnName)
    Next
    buffer.Append(vbCrLf)
    For Each dr As DataRowView In view
        For Each dc As DataColumn In view.Table.Columns
           buffer.AppendFormat("{0,15} ", dr.Row(dc))
        Next
        buffer.Append(vbCrLf)
    Next
    TextBox1.Text = buffer.ToString()End Sub
--------------------------------CS----------------------------------
  private void EnumerateView(DataView view)
  {
     var buffer = new System.Text.StringBuilder();
     foreach (DataColumn dc in view.Table.Columns)
     {
        buffer.AppendFormat("{0,15} ", dc.ColumnName);
     }
     buffer.Append("\r\n");
     foreach (DataRowView dr in view)
     {
        foreach (DataColumn dc in view.Table.Columns)
        {
           buffer.AppendFormat("{0,15} ", dr.Row[dc]);
        }
                buffer.Append("\r\n");
     }
     textBox1.Text = buffer.ToString();
  }

--------------------------------------------------------------------

1 comentario: