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

Lección 2: serialización, tipos especializados, y enlace de datos

Serializar y deserializar el DataTable con datos XML
El contenido de un DataTable se puede escribir un archivo XML o una secuencia,mediante el método WriteXml:
---------------------------------VB---------------------------------
 'metodo para crear nombres de archivos en el escritorio
 Private Function desktopFileName(ByVal fileName As String)As String
   Return Path.Combine(Environment.GetFolderPath   (Environment.SpecialFolder.Desktop),fileName)
 End Function
  'escribo un xml
 cars.WriteXml(desktopFileName("Cars.xml”))
---------------------------------CS---------------------------------
 //metodo para crear nombres de archivos en el escritorio
 private string desktopFileName(string fileName)
{
   returnPath.Combine(
   Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
   fileName);
}
 //escribo el xml
 cars.WriteXml(desktopFileName("Cars.xml"));
--------------------------------------------------------------------

Si este código se ejecuta con DataSet definido en la lección anterior, el archivo cars.xml se verá así:
xml version="1.0" standalone="yes"?>
<DocumentElement>
  <Cars>
    <Vin>123456789ABCD<Vin>
    <Make>Ford<Make>
    <Year>2002<Year>
    <Year_x0020_and_x0020_Make>2002 Ford<Year_x0020_and_x0020_Make>
    <Cars>
  <Cars>
    <Vin>987654321XYZ<Vin>
    <Make>Jeep<Make>
    <Year>2002<Year>
    <Year_x0020_and_x0020_Make>2002 Jeep<Year_x0020_and_x0020_Make>
    <Cars>
<DocumentElement>

En este ejemplo se utiliza DocumentElement como el elemento raíz y Cars para cada fila de datos. Un nombre de elemento XML no puede contener caracteres de espacio, por lo que “Year and Make” se convierten automáticamente a Year_x0020_and_x0020_Make.
Puede ajustar la salida XML, proporcionando un esquema XML o establecer las propiedades de la tabla de datos y sus columnas. Para cambiar los atributos Vin, Marca y año se puede establecer la propiedad ColumnMapping cada DataColumn de MappingType.Attribute.
La columna ”Year and Make”  es una columna calculada, por lo que sus datos no necesitan ser almacenados,para esto se debe establecer su propiedad ColumnMapping a MappingType.Hidden.

Nombre
Descripción
Element
La columna se asigna a un elemento XML.
Attribute
La columna se asigna a un atributo XML.
SimpleContent
La columna se asigna a un nodo XmlText.
Hidden
La columna se asigna a una estructura interna.

Es importante entender que la propiedad ColumnMapping sólo afecta  al formato de los datos al escribir en XML.
---------------------------------VB---------------------------------
'seteo el nombre de la tabla y la forma de mapear columnas
cars.TableName = "Auto"
cars.Columns("Vin").ColumnMapping= MappingType.Attribute
cars.Columns("Make").ColumnMapping = MappingType.Attribute
cars.Columns("Year").ColumnMapping = MappingType.Attribute
cars.Columns("Year and Make").ColumnMapping= MappingType.Hidden
---------------------------------CS---------------------------------
//seteo el nombre de la tabla y la forma de mapear columnas
car.TableName = "Auto";
car.Columns["Vin"].ColumnMapping= MappingType.Attribute;
car.Columns["Make"].ColumnMapping = MappingType.Attribute;
car.Columns["Year"].ColumnMapping = MappingType.Attribute;
car.Columns["Year and Make"].ColumnMapping= MappingType.Hidden;
--------------------------------------------------------------------

El XML quedaría de esta forma:
<xml version="1.0" standalone="yes"?>
<DocumentElement>
  <Auto Vin="123456789ABCD" Make="Ford" Year="2002" />
  <Auto Vin="987654321XYZ" Make="Jeep" Year="2002" />
<DocumentElement>

El XML es bastante compacto, pero los tipos de datos no se guardan y todos se consideran string.Para almacenar el esquema XML con los datos y sus tipos, se agrega la enumeración XmlWriteMode.WriteSchema al guardar:
---------------------------------VB---------------------------------
cars.WriteXml(desktopFileName("CarWithSchema.xml"), XmlWriteMode.WriteSchema)
---------------------------------CS---------------------------------
car.WriteXml(desktopFileName("CarWithSchema.xml"), XmlWriteMode.WriteSchema);
--------------------------------------------------------------------

Guardándolo de esta forma el xml quedaria:
<xml version="1.0" standalone="yes"?>
<NewDataSet>
  <xs:schema id="NewDataSet" xmlns=""
  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet"msdata:IsDataSet="true"
    msdata:MainDataTable="Auto" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Auto">
            <xs:complexType>
              <xs:attribute name="Vin" msdata:Caption="VIN" use="required">
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:maxLength value="23" />
                  <xs:restriction>
                <xs:simpleType>
              <xs:attribute>
              <xs:attribute name="Make" use="required">
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:maxLength value="35" />
                  <xs:restriction>
                <xs:simpleType>
              <xs:attribute>
              <xs:attribute name="Year" type="xs:int" use="required" />
              <xs:attribute name="Year_x0020_and_x0020_Make"
              msdata:ReadOnly="true"
              msdata:Expression="Year + ' ' + Make"use="prohibited">
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:maxLength value="70" />
                  <xs:restriction>
                <xs:simpleType>
              <xs:attribute>
            <xs:complexType>
          <xs:element>
        <xs:choice>
      <xs:complexType>
      <xs:unique name="Constraint1" msdata:PrimaryKey="true">
        <xs:selector xpath=".//Auto" />
        <xs:field xpath="@Vin" />
      <xs:unique>
    <xs:element>
  <xs:schema>
  <Auto Vin="123456789ABCD" Make="Ford" Year="2002" />
  <Auto Vin="987654321XYZ" Make="Jeep" Year="2002" />
<NewDataSet>

Con el esquema XML incluido, todos los tipos de datos están definidos y un DataTable se podría cargar sin  problemas desde este archivo:
---------------------------------VB---------------------------------
Dim xmlTableAs New DataTable()
xmlTable.ReadXml(desktopFileName("CarWithSchema.xml"))
---------------------------------CS---------------------------------
DataTable xmlTable = newDataTable();
xmlTable.ReadXml(desktopFileName("CarWithSchema.xml"));
--------------------------------------------------------------------

Serialización y deserialización de DataSet
Un DataSet puede ser guardado o serializado, como XML o como datos binarios en un  stream o archivo, sino que también se puede cargar o deserializar, con datos XML o binarios de un stream  o archivo.
Pueden ser transferidos a través de una red de varios protocolos, incluyendo HTTP.

Serialización de un DataSet como XML
Se puede serializar un DataSet en un archivo XML mediante la ejecución de su método WriteXml como vimos anteriormente.
Una relación entre tablas se implementa mediante una DataRelation y cuando se guarda en un XML, las relaciones primaria-secundaria se representan mediante elementos primarios que contienen elementos secundarios anidados.
Para facilitar el anidamiento de objetos secundarios se establece la propiedad Nested como true, las filas secundarias de la relación se anidan dentro de la columna primaria cuando se escriben comodatos XML. La propiedad Nested de la DataRelation es false de manera predeterminada.

---------------------------------VB---------------------------------
vendorData.Relations("vendor_part").Nested= True
For Each dt As DataTable InvendorData.Tables
   ForEach dc AsDataColumn In dt.Columns
       IfNot (dc.DataType.Equals(GetType(Guid))) Then
          dc.ColumnMapping= MappingType.Attribute
       EndIf
   Next
Next
vendorData.WriteXml(desktopFileName("Vendors1.xml"),_
XmlWriteMode.IgnoreSchema)

---------------------------------CS---------------------------------
//anido los datos y los atributos xml
vendorData.Relations["vendor_part"].Nested= true;
foreach (DataTable dt in vendorData.Tables)
{
   foreach(DataColumn dc in dt.Columns)
   {
       if(dc.DataType != typeof(Guid))
         dc.ColumnMapping = MappingType.Attribute;
   }
}
vendorData.WriteXml(desktopFileName("Vendors1.xml"),
XmlWriteMode.IgnoreSchema);

--------------------------------------------------------------------
De esta forma quedaría el XML con las relaciones anidadas:
<xml version="1.0" standalone="yes"?>
<VendorData>
  <Vendor Name="Tailspin Toys">
    <Id>d012b54d-c855-4c1f-969e-74554d2cb0c7<Id>
    <Part PartCode="WGT1" PartDescription="Widget 1Description"
    Cost="10" RetailPrice="12.32">
      <Id>167583e9-f4eb-4004-9efa-5477e0f55208<Id>
      <VendorId>d012b54d-c855-4c1f-969e-74554d2cb0c7<VendorId>
    <Part>
    <Part PartCode="WGT2" PartDescription="Widget 2Description"
    Cost="9" RetailPrice="11.32">
      <Id>d3b42db7-b23f-4c33-9961-f7a325342167<Id>
      <VendorId>d012b54d-c855-4c1f-969e-74554d2cb0c7<VendorId>
    <Part>
  <Vendor>
<VendorData>
Para poder pasar los tipos de datos se la para como parámetro XmlWriteMode.WriteSchema , el archivo XML resultante es mucho mas grande.
Se puede utilizar el método WriteXmlSchema del DataSet para extraer la definición de esquema XML en un archivo separado.

---------------------------------VB---------------------------------
vendorData.WriteXmlSchema(desktopFileName("VendorSchema.xsd"))
---------------------------------CS---------------------------------
vendorData.WriteXmlSchema(desktopFileName("VendorSchema.xsd"));
--------------------------------------------------------------------

Serialización de un DataSet como un DiffGram
Un DiffGram es un documento XML que contiene todos los datos del dataset, incluida la información DataRow original (DataRowVersion).Un DataSet se puede serializar como un DiffGram simplemente pasando XmlWriteMode.DiffGram al método WriteXml.
---------------------------------VB---------------------------------
vendorData.WriteXml(desktopFileName("VendorSchema.xsd"),
XmlWriteMode.DiffGram)
---------------------------------CS---------------------------------
vendorData.WriteXml(desktopFileName("VendorSchema.xsd")
XmlWriteMode.DiffGram);
--------------------------------------------------------------------

Ejemplo de como se vería un XML DiffGram:
<xml version="1.0" standalone="yes"?>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
  <VendorData>
    <Vendor diffgr:id="Vendor1" msdata:rowOrder="0" Name="Tailspin Toys">
      <Id>9e3fe885-8ffd-4c58-9cbf-a486dcbc930e<Id>
      <Part diffgr:id="Part1" msdata:rowOrder="0" diffgr:hasChanges="modified"
      PartCode="WGT1" PartDescription="Widget 1Description"
      Cost="12" RetailPrice="12.32">
        <Id>4e91d3ca-a4a0-416e-ad4d-cebf047afcf4<Id>
        <VendorId>9e3fe885-8ffd-4c58-9cbf-a486dcbc930e<VendorId>
      <Part>
    <Vendor>
  <VendorData>
  <diffgr:before>
    <Part diffgr:id="Part1" msdata:rowOrder="0" PartCode="WGT1"
    PartDescription="Widget 1 Description"Cost="10" RetailPrice="12.32">
      <Id>4e91d3ca-a4a0-416e-ad4d-cebf047afcf4<Id>
      <VendorId>9e3fe885-8ffd-4c58-9cbf-a486dcbc930e<VendorId>
    <Part>
    <Part diffgr:id="Part2" diffgr:parentId="Vendor1" msdata:rowOrder="1"
          PartCode="WGT2" PartDescription="Widget 2 Description" Cost="9"
          RetailPrice="11.32">
      <Id>75a54b24-f8bd-4bbd-8427-20a277a44908<Id>
      <VendorId>9e3fe885-8ffd-4c58-9cbf-a486dcbc930e<VendorId>
    <Part>
  <diffgr:before>
<diffgr:diffgram>

Deserializar DataSet a partir de XML
Un dataset se puede crear fácilmente mediante la deserialización de un archivo XML o un stream:
---------------------------------VB---------------------------------
'lee un xml y carga el dataset
Dim vendorData As New DataSet()
vendorData.ReadXmlSchema(desktopFileName("VendorSchema.xsd"))
vendorData.ReadXml(desktopFileName("Vendors3.xml"),_
XmlReadMode.IgnoreSchema)
---------------------------------CS---------------------------------
//lee un xml y carga el dataset
DataSet vendorData = new DataSet();
vendorData.ReadXmlSchema(desktopFileName("VendorSchema.xsd"));
vendorData.ReadXml(desktopFileName("Vendors3.xml"),
XmlReadMode.IgnoreSchema);
--------------------------------------------------------------------

Nombre
Descripción
Auto
Predeterminado. El XML es examinado por el método ReadXml y se selecciona el modo apropiado.
ReadSchema
Lee cualquier esquema en línea y carga los datos. Si el DataSet ya contiene un esquema, se pueden agregar al mismo las nuevas tablas, aunque se producirá una excepción si cualquier tabla del esquema en línea ya existe en el DataSet.
IgnoreSchema
Omite cualquier esquema y lee los datos del esquema del DataSet existente. Si los datos no coinciden con el esquema existente, se descartan
InferSchema
Omite cualquier esquema, deduce el esquema a partir de los datos y los carga.
DiffGram
Lee un DiffGram, aplicando los cambios del DiffGram a DataSet. La semántica es idéntica a la de una operación Merge. Al igual que ocurre con la operación Merge, se conservan los valores RowState.
Fragment
Lee fragmentos XML, como los que se generan al ejecutar consultas  en una instancia de SQL Server. Al establecer XmlReadMode en Fragment, se lee el espacio de nombres predeterminado como el esquema en línea.
InferTypedSchema
Omite cualquier esquema, deduce el esquema con establecimiento inflexible de tipos a partir de los datos y los carga. Si el tipo no se puede deducir de los datos, se interpreta como datos de cadena. Si el DataSet ya contiene un esquema, se extiende el esquema actual mediante la adición de nuevas tablas o columnas a las tablas existentes.

Serializar el DataSet como datos binarios
Aunque el conjunto de datos se puede serializar en XML, en muchos casos, el tamaño del archivo XML causa problemas con los recursos como la memoria y espacio en el disco o ancho de banda cuando se mueve estos datos a través de la red. Si el XML no es necesario,el conjunto de datos se puede serializar como un archivo binario:
---------------------------------VB---------------------------------
'agrego los Imports
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO
Dim fsas new FileStream(_
desktopFileName("VendorData.bin",FileMode.Create)
Dim fmtAs New BinaryFormatter()
‘si no colocamos serializationFormat.Binary, el archivo binario
‘tiene un formato BinaryXML (un archivo que guarda xml adentro),
‘pero de esta forma queda con TrueBinary
vendorData.RemotingFormat = SerializationFormat.Binary
fmt.Serialize(fs, vendorData)
fs.Close()
---------------------------------CS---------------------------------
//agrego los using
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
 
FileStream fs = new FileStream(
desktopFileName("VendorData.bin"),FileMode.Create);
BinaryFormatter fmt = new BinaryFormatter();
//si no colocamos serializationFormat.Binary, el archivo binario
//tiene un formato BinaryXML (un archivo que guarda xml adentro),
//pero de esta forma queda con TrueBinary
vendorData.RemotingFormat = SerializationFormat.Binary;
fmt.Serialize(fs, vendorData);
 
fs.Close( );
--------------------------------------------------------------------

Deserializar un DataSet a partir de datos binarios
El archivo de datos binarios que ha guardado en el ejemplo anterior puede ser serializado dentro de un dataset. El BinaryFormatter almacena el esquema de forma automática, así que no hay necesidad de cargar un primer esquema. El BinaryFormatter automáticamente identifica el archivo como si hubiera sido guardado como BinaryXml o TrueBinary:
---------------------------------VB---------------------------------
'deserializar un archivo binario
Dim vendorData As DataSet
Dim fsAs New FileStream(_
desktopFileName("VendorData.bin"),FileMode.Open)
Dim fmtAs New BinaryFormatter()
vendorData = CType(fmt.Deserialize(fs),DataSet)
fs.Close()
---------------------------------CS---------------------------------
 DataSet vendorData;
 FileStream fs = new FileStream(
desktopFileName("VendorData.bin"), FileMode.Open);
 BinaryFormatterfmt = newBinaryFormatter();
vendorData = (DataSet)fmt.Deserialize(fs);
 fs.Close();
--------------------------------------------------------------------

Recorriendo datos con la clase DataTableReader
La clase DataTableReader permite recorrer DataRows en una o más DataTable. Contiene un método llamado Read que se ejecuta para cargar  de a una fila de datos y luego la posición se puede ir avanzando.Si se llega al final, el método Read devuelve un valor nulo.
La clase DataSet contiene un método llamado CreateDataReader que devuelve una instancia de la clase DataTableReader. Si el conjunto de datos contiene más de una tabla, el DataTableReader lee las filas del primer DataTable, y se puede utilizar el método NextResult para continua recorriendo todas las DataTable del dataset.
---------------------------------VB---------------------------------
 'leo los datos delDataTable
 Dim rd As DataTableReader=masterData.CreateDataReader()
 While (rd.Read())
    TextBox1.AppendText(rd("Name").ToString()+ vbCrLf)
End While
 rd.NextResult()
 While (rd.Read())
    TextBox1.AppendText(rd("PartName").ToString()+ vbCrLf)
 End While
---------------------------------CS---------------------------------
 //leo los datos en elDataTable
 DataTableReader rd= masterData.CreateDataReader();
 while (rd.Read())
{
    textBox1.AppendText(rd["Name"].ToString()+ "\r\n");
}
rd.NextResult();
 while (rd.Read())
{
    textBox1.AppendText(rd["PartName"].ToString()+ "\r\n");
 }
-------------------------------------------------------------------

Manejo de tipos especializados

La clase DataTable permite tener columnas cuyo tipo sea especializado y requiere un tratamiento especial en algunos casos, porque si el tipo de datos de una columna se utiliza como una clave principal o como un RowFilter para una vista de datos, cualquier cambio en el valor de la columna debe incluir la asignación de un nuevo objeto a la columna en lugar de sólo cambiar las propiedades existentes en esta. Esta asignación es necesaria para activar la actualización de los índices internos utilizados por ordenar, filtrar, y las operaciones de primary key.

---------------------------------VB---------------------------------

<Serializable()>
Public Class Car
    Public Property Make() As String
    Public Property Model() As String
    Public Property Year() As Integer
End
Class

---------------------------------CS---------------------------------

[Serializable]
    public class Car
    {
        public int Year { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
    }

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

Data Bindings

La mayoría de los controles que se utilizan en formularios Windows Forms, ASP.NET o Windows Presentation Foundation (WPF) son enlazables a datos.

Enlace de datos en aplicaciones de Windows Forms y Web Forms (ASPX)

Para enlazar controles en una aplicación de Windows Forms, se debe establecer la propiedad DataSource del control a un objeto que implemente la interfaz IList. Además, puede que se tengan que establecer otras propiedades, dependiendo del tipo de control y la fuente de los datos:

·         DataSource: propiedad a la que se le asignan los datos (cualquier elemento que implemente la interface IListSource, IBindingList, IBindingListView  e IEnumerable en ASPX).

·         DataMember: cuando de asigna la propiedad DataSource, si el objeto contiene mas de una columna se debe especificar cual se va a usar (se coloca el nombre de la columna a usar).

·         DisplayMember: se usa en controles como los ComboBox y ListBox (DropDownList y
ListBox en ASPX), para indicar que columna va a ser mostrada.

·         ValueMember: En ComboBoxs y ListBoxs (DropDownList y ListBox en ASPX), indica la columna que será devuelta cuando un valor es seleccionado.

Enlace de datos en Windows Presentation Foundation (WPF)


Las aplicaciones WPF requieren un objetivo y una fuente en el DataBinding. El destino de enlace puede ser de cualquier propiedad accesible (publica) derivada de DependencyProperty, puede unirse a los dataSet y dataTables, y puede unirse a Common Language Runtime (CLR), los XAML. Para enlazar los controles se puede utilizar la propiedad ItemsSource .

 

Resumen de la lección
En esta lección se proporciona información acerca de la serialización y deserialización de las clases ADO.NET desconectadas, así como sobre el manejo de los tipos de datos especializados en un DataSet y DataTable.

·         Los DataSets y DataTables se pueden serializar y deserializar desde y hacia un archivo binario o XML o una secuencia.

·         El valor de la columna puede contener objetos personalizados.

·         Puede utilizar DataTableReader para recorrer una dataTable.y rellenar ventanas y controles Web.

·         La mayoría de los controles de interfaz gráfica de usuario tiene una propiedad DataSource y la propiedad DataMember, que son utilizadas para el enlace de datos.

 

No hay comentarios:

Publicar un comentario