Apuntes de ADO.NET

Llop Site Home > Visual Studio .NET > Apuntes > ADO.NET 16-Feb-2005

16 Febrero 2005



Con la lección de hoy aprendemos a crear bases de datos en el servidor desde una aplicación local,
las múltiples prestaciones de la clase 'DataAdapter', más detalles sobre cómo crear ficheros XML 
para almacenar 'DataSet's, y el funcionamiento de las aplicaciones remotas, tanto a nivel de servidor 
como de cliente.

    Índice de programas de prueba:
        * DDL: Data Definition Lanaguage.
        * TestDA: Aprendiendo a exprimir los recursos de DataAdapter.
        * Intro XML: De 'DataSet's y de cómo éstos leen y escriben '.xml's y '.xsd's.
        * Remoting: Accedediendo a objetos remotos desde una aplicación local.

DDL: Data Definition Language

Imports System.Data
Imports System.Data.SqlClient

Public Class Form1 : Iherits System.Windows.Forms.Form
    'Constantes para no tener que picar cada vez el salto de línea y la tabulación.
    Const l As String = vbCrLf
    Const t As String = vbTab

#Region " Código generado por el Diseñador "
    Public Sub New()
        MyBase.New()
        'Se inicializan los componentes creados con el 'Diseñador'.
        InitializeComponent()
    End Sub

    ''Dispose' se sobrecarga para eliminar los componentes en la lista. 
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Contenedor para los componentes.
    Private components As System.ComponentModel.IContainer
    'Código del 'Diseñador'; no tocar con el 'Editor de código'.
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents Label1 As System.Windows.Forms.Label
    Friend WithEvents Button1 As System.Windows.Forms.Button

    'Método que inicializa los componentes creados con el 'Diseñador'.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.TextBox1 = New System.Windows.Forms.TextBox
        Me.Label1 = New System.Windows.Forms.Label
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        'TextBox1
        Me.TextBox1.BackColor = System.Drawing.Color.FromArgb(CType(224, Byte), CType(224, Byte), CType(224, Byte))
        Me.TextBox1.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.TextBox1.ForeColor = System.Drawing.Color.Navy
        Me.TextBox1.Location = New System.Drawing.Point(264, 8)
        Me.TextBox1.Multiline = True
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both
        Me.TextBox1.Size = New System.Drawing.Size(424, 328)
        Me.TextBox1.TabIndex = 0
        Me.TextBox1.Text = ""
        'Label1
        Me.Label1.BackColor = System.Drawing.Color.FromArgb(CType(255, Byte), CType(224, Byte), CType(192, Byte))
        Me.Label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D
        Me.Label1.Font = New System.Drawing.Font("Microsoft Sans Serif", 10.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.Label1.ForeColor = System.Drawing.Color.Maroon
        Me.Label1.Location = New System.Drawing.Point(0, 8)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(248, 40)
        Me.Label1.TabIndex = 1
        Me.Label1.Text = "1.-DDL"
        Me.Label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
        'Button1
        Me.Button1.Location = New System.Drawing.Point(0, 56)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(128, 24)
        Me.Button1.TabIndex = 4
        Me.Button1.Text = "2.- Ejemplos"
        'Form1
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.AutoScroll = True
        Me.ClientSize = New System.Drawing.Size(696, 357)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.TextBox1)
        Me.Controls.Add(Me.Label1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)
    End Sub
#End Region
    'Subrutina que pone un texto en el TextBox1.
    Sub Mostrar()
        Me.TextBox1.Text = ""
        Me.TextBox1.AppendText("En lugar de querys a los objetos del servidor, se pretende administrarlos: CREATE TABLE, CRETE PROCEDURE, CREATE INEX, ALTER TABLE" & l & l)
        Me.TextBox1.AppendText("CREATE TABLE" & l & "maneja tablas, columnas, restricciones")
    End Sub

    'Al cargar el Form1, se pega una texto en el TextBox1 mediante la sub superior.
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Mostrar()
    End Sub

    'Responde al click sobre el Button1.
    'Crea una tabla -'test'-, y un procedimiento -'InsertCategory'-, en la base de datos 'Northwind'.
    Private Sub eje1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Declara una conexión, y un comando.
        Dim cn As New SqlConnection
        Dim cm As SqlCommand

        'Se conecta a la base de datos 'Northwind', en el servidor del equipo local.
        cn.ConnectionString = "Data Source=localhost,1433;Integrated Security=True; Database=Northwind"
        cn.Open()

        'Con este comando omitido, borraríamos 'InsertCategory' y 'test' antes de crear 'test' de nuevo.
        'Dim tx As String = "DROP PROC InsertCategory; "
        'tx &= "DROP TABLE test; "
        'tx &= "CREATE TABLE test (campo1 int);  "
        'Solamente crearemos 'test', una tabla con un campo numérico.
        Dim Tx As String = "CREATE TABLE test (campo1 int);  "

        'Otro comando; este crea un procedimiento para insertar un nuevo valor a 'Categories'.
        Dim createStr As String = "CREATE PROCEDURE InsertCategory  " & _
                          "  @CategoryName nchar(15), " & _
                          "  @Identity int OUT " & _
                          "AS " & _
                          "INSERT INTO Categories (CategoryName) VALUES(@CategoryName) " & _
                          "SET @Identity = @@Identity " & _
                          "RETURN @@ROWCOUNT"

        'Los comandos SQL: uno creará el procedimiento, y el otro la tabla.
        Dim CMD As SqlCommand = New SqlCommand(createStr, cn)
        cm = New SqlCommand(tx, cn)

        'Intentamos ejecutar las instrucciones de Transact-SQL en la conexión.
        Try
            cm.ExecuteNonQuery()
            CMD.ExecuteNonQuery()
        Catch ex As SqlException
            'Si algo ha fallado, mostramos los detalles de todos los errores en la 'SQLException'.
            Dim se As SqlError
            For Each se In ex.Errors
                Me.TextBox1.Text &= l & "Severidad" & se.[Class] & l
                Me.TextBox1.Text &= "Mensaje" & se.Message & l
                Me.TextBox1.Text &= "Número" & se.Number & l
                Me.TextBox1.Text &= "Servidor" & se.Server & l
                Me.TextBox1.Text &= "Provider" & se.Source & l
            Next
        Finally
            'Se cierra la conexión, y se elimina.
            cn.Close() : cn.Dispose()
        End Try
    End Sub
End Class



Paginar : Traer una cantidad de datos limitada dentro de una BD.
¿Cuándo es conveniente paginar? Cuando la BD es bastante grande, y, por cuestiones de rendimiento,
no sale a cuenta traerla toda.

TestDA: Aprendiendo a exprimir los recursos de DataAdapter


Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.OleDb

Public Class Form1 : Inherits System.Windows.Forms.Form
    'INTRODUCCIÓN a la clase DataAdapter
    '
    'La misión es llenar objetos DataTable desde una base de datos. Una vez hecha la 
    'transferencia de información la conexión se cierra, trabajando el cliente en modo 
    'desconectado. Tras los cambios, estos son grabados usando la misma clase DA.
    '
    'Hay un DA por cada Provider, porque DA debe saber como conectarse y desconectarse
    'a la fuente de datos.

#Region " Código generado por el Diseñador "
    Public Sub New()
        MyBase.New()
        'Se inicializan los componentes creados con el 'Diseñador'.
        InitializeComponent()
    End Sub

    ''Dispose' se sobrecarga para eliminar los componentes en la lista. 
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Contenedor para los componentes.
    Private components As System.ComponentModel.IContainer
    'Código del 'Diseñador'; no tocar con el 'Editor de código'.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents Button3 As System.Windows.Forms.Button
    Friend WithEvents SqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter
    Friend WithEvents SqlSelectCommand1 As System.Data.SqlClient.SqlCommand
    Friend WithEvents SqlConnection1 As System.Data.SqlClient.SqlConnection
    Friend WithEvents Button5 As System.Windows.Forms.Button
    Friend WithEvents SqlDataAdapter2 As System.Data.SqlClient.SqlDataAdapter
    Friend WithEvents SqlSelectCommand2 As System.Data.SqlClient.SqlCommand
    Friend WithEvents DataSet11 As TestDA.DataSet1
    Friend WithEvents Button6 As System.Windows.Forms.Button
    Friend WithEvents Button7 As System.Windows.Forms.Button
    Friend WithEvents Button4 As System.Windows.Forms.Button
    Friend WithEvents Button8 As System.Windows.Forms.Button
    Friend WithEvents DataGrid2 As System.Windows.Forms.DataGrid
    Friend WithEvents Button9 As System.Windows.Forms.Button
	
    'Método que inicializa los componentes creados con el 'Diseñador'.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.DataGrid1 = New System.Windows.Forms.DataGrid
        Me.DataSet11 = New TestDA.DataSet1
        Me.Button2 = New System.Windows.Forms.Button
        Me.TextBox1 = New System.Windows.Forms.TextBox
        Me.Button3 = New System.Windows.Forms.Button
        Me.SqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter
        Me.SqlSelectCommand1 = New System.Data.SqlClient.SqlCommand
        Me.SqlConnection1 = New System.Data.SqlClient.SqlConnection
        Me.Button5 = New System.Windows.Forms.Button
        Me.SqlDataAdapter2 = New System.Data.SqlClient.SqlDataAdapter
        Me.SqlSelectCommand2 = New System.Data.SqlClient.SqlCommand
        Me.Button6 = New System.Windows.Forms.Button
        Me.Button7 = New System.Windows.Forms.Button
        Me.Button4 = New System.Windows.Forms.Button
        Me.Button8 = New System.Windows.Forms.Button
        Me.DataGrid2 = New System.Windows.Forms.DataGrid
        Me.Button9 = New System.Windows.Forms.Button
        CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.DataSet11, System.ComponentModel.ISupportInitialize).BeginInit()
        CType(Me.DataGrid2, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        'Button1
        Me.Button1.Location = New System.Drawing.Point(8, 32)
        Me.Button1.Name = "Button1"
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Intro"
        'DataGrid1
        Me.DataGrid1.DataMember = ""
        Me.DataGrid1.DataSource = Me.DataSet11.CustOrdersDetail
        Me.DataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText
        Me.DataGrid1.Location = New System.Drawing.Point(192, 264)
        Me.DataGrid1.Name = "DataGrid1"
        Me.DataGrid1.Size = New System.Drawing.Size(488, 176)
        Me.DataGrid1.TabIndex = 1
        'DataSet11
        Me.DataSet11.DataSetName = "DataSet1"
        Me.DataSet11.Locale = New System.Globalization.CultureInfo("es-ES")
        'Button2
        Me.Button2.Location = New System.Drawing.Point(8, 64)
        Me.Button2.Name = "Button2"
        Me.Button2.TabIndex = 2
        Me.Button2.Text = "Métodos"
        'TextBox1
        Me.TextBox1.Location = New System.Drawing.Point(184, 16)
        Me.TextBox1.Multiline = True
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both
        Me.TextBox1.Size = New System.Drawing.Size(480, 56)
        Me.TextBox1.TabIndex = 3
        Me.TextBox1.Text = "TextBox1"
        'Button3
        Me.Button3.Location = New System.Drawing.Point(640, 240)
        Me.Button3.Name = "Button3"
        Me.Button3.Size = New System.Drawing.Size(32, 16)
        Me.Button3.TabIndex = 4
        Me.Button3.Text = "+"
        'SqlDataAdapter1
        Me.SqlDataAdapter1.SelectCommand = Me.SqlSelectCommand1
        Me.SqlDataAdapter1.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "Customers", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("ContactName", "ContactName"), New System.Data.Common.DataColumnMapping("Phone", "Phone")})})
        'SqlSelectCommand1
        Me.SqlSelectCommand1.CommandText = "SELECT ContactName, Phone FROM Customers"
        Me.SqlSelectCommand1.Connection = Me.SqlConnection1
        'SqlConnection1
        Me.SqlConnection1.ConnectionString = "workstation id=RAUL;packet size=4096;integrated security=SSPI;data source=localho" & _
        "st;persist security info=False;initial catalog=Northwind"
        'Button5
        Me.Button5.Location = New System.Drawing.Point(112, 32)
        Me.Button5.Name = "Button5"
        Me.Button5.Size = New System.Drawing.Size(56, 23)
        Me.Button5.TabIndex = 6
        Me.Button5.Text = "DA prog"
        'SqlDataAdapter2
        Me.SqlDataAdapter2.SelectCommand = Me.SqlSelectCommand2
        Me.SqlDataAdapter2.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "CustOrdersDetail", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("ProductName", "ProductName"), New System.Data.Common.DataColumnMapping("UnitPrice", "UnitPrice"), New System.Data.Common.DataColumnMapping("Quantity", "Quantity"), New System.Data.Common.DataColumnMapping("Discount", "Discount"), New System.Data.Common.DataColumnMapping("ExtendedPrice", "ExtendedPrice")})})
        'SqlSelectCommand2
        Me.SqlSelectCommand2.CommandText = "[CustOrdersDetail]"
        Me.SqlSelectCommand2.CommandType = System.Data.CommandType.StoredProcedure
        Me.SqlSelectCommand2.Connection = Me.SqlConnection1
        Me.SqlSelectCommand2.Parameters.Add(New System.Data.SqlClient.SqlParameter("@RETURN_VALUE", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.ReturnValue, False, CType(0, Byte), CType(0, Byte), "", System.Data.DataRowVersion.Current, Nothing))
        Me.SqlSelectCommand2.Parameters.Add(New System.Data.SqlClient.SqlParameter("@OrderID", System.Data.SqlDbType.Int, 4))
        'Button6
        Me.Button6.Location = New System.Drawing.Point(112, 64)
        Me.Button6.Name = "Button6"
        Me.Button6.Size = New System.Drawing.Size(56, 23)
        Me.Button6.TabIndex = 7
        Me.Button6.Text = "DA.Fill"
        'Button7
        Me.Button7.Location = New System.Drawing.Point(112, 96)
        Me.Button7.Name = "Button7"
        Me.Button7.Size = New System.Drawing.Size(56, 23)
        Me.Button7.TabIndex = 8
        Me.Button7.Text = "DA.Missing"
        'Button4
        Me.Button4.Location = New System.Drawing.Point(8, 144)
        Me.Button4.Name = "Button4"
        Me.Button4.Size = New System.Drawing.Size(56, 23)
        Me.Button4.TabIndex = 9
        Me.Button4.Text = "Update0"
        'Button8
        Me.Button8.Location = New System.Drawing.Point(8, 96)
        Me.Button8.Name = "Button8"
        Me.Button8.TabIndex = 10
        Me.Button8.Text = "FillSchema"
        'DataGrid2
        Me.DataGrid2.DataMember = ""
        Me.DataGrid2.HeaderForeColor = System.Drawing.SystemColors.ControlText
        Me.DataGrid2.Location = New System.Drawing.Point(184, 104)
        Me.DataGrid2.Name = "DataGrid2"
        Me.DataGrid2.Size = New System.Drawing.Size(480, 120)
        Me.DataGrid2.TabIndex = 11
        'Button9
        Me.Button9.Location = New System.Drawing.Point(8, 168)
        Me.Button9.Name = "Button9"
        Me.Button9.Size = New System.Drawing.Size(56, 23)
        Me.Button9.TabIndex = 12
        Me.Button9.Text = "Update1"
        'Form1
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.AutoScroll = True
        Me.ClientSize = New System.Drawing.Size(704, 453)
        Me.Controls.Add(Me.Button9)
        Me.Controls.Add(Me.DataGrid2)
        Me.Controls.Add(Me.Button8)
        Me.Controls.Add(Me.Button4)
        Me.Controls.Add(Me.Button7)
        Me.Controls.Add(Me.Button6)
        Me.Controls.Add(Me.Button5)
        Me.Controls.Add(Me.Button3)
        Me.Controls.Add(Me.TextBox1)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.DataGrid1)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "System.Data.SqlCliente.SqlDataAdapter"
        CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.DataSet11, System.ComponentModel.ISupportInitialize).EndInit()
        CType(Me.DataGrid2, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)
    End Sub
#End Region

    'DA para bases de datos SQL.
    Dim DA, daSQL As SqlDataAdapter
    'DA para bases de datos OLE.
    Dim daExcel As OleDb.OleDbDataAdapter
    'DS para almacenar las consultas a las BD.
    Dim ds As New DataSet
    ''daUpdate' actualizará la BD; 'dsUpdate' actualizará el DataSet
    Dim daUpdate As SqlDataAdapter, dsUpdate As DataSet

    'Este método responde al click sobre el botón "intro".
    'Llena un mismo DataSet con datos obtenidos de fuentes dispares (una tabla de Excel,
    'y otra de SQL).
    Private Sub intro(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'EXCEL
        'Nótese en la cadena de conexión que la tabla Excel está en el mismo directorio que la aplicación.
        Dim cnstrExcel As String
        cnstrExcel = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
            "Data Source=" & Application.StartupPath & _
            "\ListasDePrecios.xls;Extended Properties=Excel 8.0;"
        'Se inicializa el objeto conexión. Gracias a éste, se inicializa el DA para la tabla 
        'de Excel 'Tarifas' -se recomienda poner el nombre de la tabla entre corchetes.
        Dim objConn As New System.Data.OleDb.OleDbConnection(cnstrExcel)
        daExcel = New OleDb.OleDbDataAdapter("SELECT * FROM [Tarifas$]", objConn)
        'Se crea un DataSet, y se le añade la tabla que viene de Excel.
        Dim ds As New DataSet
        Try
            daExcel.Fill(ds, "TablaExcel")
        Catch ex As OleDbException
        End Try

        'Ahora tres cuartos de lo mismo para llenar el DS con la tabla SQL.
        Dim cn As New SqlConnection
        cn.ConnectionString = "Integrated Security=false;" & _
            "Initial Catalog=Northwind;" & _
            "Data Source=localhost,1433; user id=sa; password=1234"
        daSQL = New SqlDataAdapter("SELECT * FROM Customers", cn)
        'Rellenamos el 'DataSet', con los datos del 'DataAdapter'. Pero, ¿no se machacará la
        ''TablaExcel'? No: 'DataSet' puede almacenar más de una tabla al mismo tiempo.
        Try
            daSQL.Fill(ds, "TablaSQL")
        Catch ex As SqlException
        End Try

        'Se rellena el 'DataGrid' con el 'DS'. También se le podría pasar:
        '	  Una 'DataTable',
        '	  un 'DataView',
        '	  un 'DataViewManager',
        '	  y cualquier componente que implemente la interfaz IListSource, o IList.
        With Me.DataGrid1
            .DataSource = ds
        End With
    End Sub

    Private Sub métodos(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        With DA
            'PROPIEDADES
            'SelectCommand, UpdateCommand, DeleteCommand, InsertCommand.
            '   El TextBox1 enseñará las declaraciones SQL para SELECT, UPDATE, DELETE, INSERT la BBDD.
            'Me.TextBox1.AppendText(.SelectCommand.ToString & vbCrLf)
            'Me.TextBox1.AppendText(.UpdateCommand.ToString & vbCrLf)
            'Me.TextBox1.AppendText(.DeleteCommand.ToString & vbCrLf)
            'Me.TextBox1.AppendText(.InsertCommand.ToString & vbCrLf)

            'TableMappings
            '   Mantiene la correspondencia entre las columnas y tablas del DataSet
            '   y las equivalentes de la fuente de datos. Inicializamos una instancia de 
            '   'DataTableMappingCollection' con los 'TableMappings' de este 'DataAdapter'.
            'Dim tm As System.Data.Common.DataTableMappingCollection
            'tm = .TableMappings

            'MissingMappingAction()
            '   La acción a seguir cuando los datos no se casan con con una
            '   tabla o columna. Las acciones se enumeran como:
            '
            'Se genera una InvalidOperationException error:
            '.MissingMappingAction = MissingMappingAction.[Error]
            '
            'Columna o tabla ignorada si no tiene correspondencia, devuelve null:
            '.MissingMappingAction = MissingMappingAction.Ignore
            '
            'Se crea la tabla o columna no existente, añadiéndose al dataset con
            'su nombre original:
            '.MissingMappingAction = MissingMappingAction.Passthrough

            'MissingSchemaAction
            '   Acción a tomar cuando el Schema del DataSet no concuerda
            '
            'Se añaden las columnas que hagan falta para completar el schema.
            '.MissingSchemaAction = MissingSchemaAction.Add
            '
            'Se añaden las columnas que hagan falta para completar el schema 
            'junto con la clave primaria.
            '.MissingSchemaAction = MissingSchemaAction.AddWithKey
            '
            'Se genera una InvalidOperationException error.
            '.MissingSchemaAction = MissingSchemaAction.[Error]
            '
            'Se obvian las columnas extras.
            '.MissingSchemaAction = MissingSchemaAction.Ignore

            'AcceptChangesDuringFill
            ' Determina si el método AcceptChanges es llamado cuando un DataRow es
            '   añadido a la tabla
            'Dim bo As Boolean = .AcceptChangesDuringFill()
        End With

        'MÉTODOS

        'Fill
        '   Añade rows al DataSet; en los argumentos puedes definir el registro a partir
        '   del que copiar, y cuántos copiar.
        'Dim cuantasFilasLeidas As Integer = DA.Fill(ds, 0, 100, "TablaASerRellenada")

        '¿Cómo utilizaríamos la construcción anterior para introducir navegación?
        'ver AvanzarAPagina()
        'Pasa que si la base de datos es muy grande, el 'DataSet' será enorme, y eso en
        'pocos casos es práctico.

        '¿Cómo implementaríamos una paginación más avanzada?
        'Update
        '   Actualiza la fuente de dtos con los comandos INSERT, UPDATE o DELETE
        '   necesarios
        '.Update(ds) 'ver sobrecarga del constructor
    End Sub
	
    'Típica función para paginar: vemos que avanza de 5 en 5 registros.
    Function AvanzarAPagina(ByVal n As Integer) As Integer
        Return daExcel.Fill(ds, (n - 1) * 5, 5, "TablaExcel")
    End Function
	
    'Método que responde al pulsar el botón 3; 'DataGrid' muestra los datos correspondientes a la página 3.
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        AvanzarAPagina(3)
        Me.DataGrid1.DataSource = ds
    End Sub
  
    'Salta al pulsar el 'Button5'. Lo que hace es rellenar el 'DataGrid1' con datos devueltos por
    'un 'procedimiento almacenado' de la base de datos.
    Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Dim daProg As New SqlDataAdapter
        Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true")

        'Comando normal y corriente:
        'Dim cm As New SqlCommand("SELECT * FROM Products", cn)
        'Variante si se trata de un 'stored procedure':
        Dim cmStoreProcedure As SqlCommand
        cmStoreProcedure.CommandText = "CustOrdersOrders"
        cmStoreProcedure.CommandType = CommandType.StoredProcedure
        daProg.SelectCommand = cmStoreProcedure

        Try
            daProg.Fill(ds)
            Me.DataGrid1.DataSource = ds
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    'Responde al pulsar sobre el 'Button6'. De nuevo se rellena el 'DataGrid1', sólo que esta 
    'vez se toman medidas para optimizar la carga de datos en el 'DataSet'.
    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
        Dim daProg As New SqlDataAdapter
        Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true")
        Dim cm As New SqlCommand("SELECT * FROM Customers", cn)
        daProg.SelectCommand = cm
        Dim ds As New DataSet
        ds.Tables.Add(New DataTable("Clientes"))

        'Optimizaciones del método Fill
        Try
            'Las restricciones no se tendrán en cuenta a la hora de hacer actualizaciones a 'ds'.
            ds.EnforceConstraints = False
            'Se desactivan notificaciones, mantenimiento de índices y restricciones.
            ds.Tables(0).BeginLoadData()
            'Se cargan los datos.
            daProg.Fill(ds, "Clientes")
            'Al terminar la carga de datos, se activan notificaciones, mantenimiento de índices y restricciones.
            ds.Tables(0).EndLoadData()
            Me.DataGrid1.DataSource = ds.Tables(0).DefaultView
        Catch ex As SqlException
            MsgBox(ex.Message)
        End Try
    End Sub

    'Con esta subrutina, que responde al click en 'Button7', se pretende mostrar lo que se puede 
    'hacer cuando el 'esquema' de un 'DataSet' no coincide con el de los datos para rellenarlo.
    Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click
        Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true")
        Dim ds As New DataSet
        ds.Tables.Add("Clientes")
        ds.Tables("Clientes").Columns.Add(New DataColumn("nombre", GetType(String)))
        Dim da As New SqlDataAdapter

        'Probar las variantes
        'da.MissingSchemaAction = MissingSchemaAction.[Error]
        'da.MissingSchemaAction = MissingSchemaAction.AddWithKey
        da.MissingSchemaAction = MissingSchemaAction.Ignore
        da.SelectCommand = New SqlCommand("SELECT * FROM Products", cn)

        'Como la tabla 'Clientes' de 'ds' tiene un esquema ya, lo que se va a mostrar en el
        ''DataGrid1' dependerá del 'MissingSchemaAction' utilizado.
        Try
            da.Fill(ds.Tables("Clientes"))
            Me.DataGrid1.DataSource = ds
        Catch ex As SqlException
            MsgBox(ex.Message)
        End Try

        'En el siguiente bloque, el 'Schema' se añadirá a 'ds' antes que los datos.
        Dim da2 As New SqlDataAdapter
        Dim cm2 As New SqlCommand("Select * From Employees", cn)
        da2.SelectCommand = cm2
        Try
            da2.FillSchema(ds, SchemaType.Mapped)
            da2.Fill(ds)
            Me.DataGrid1.DataSource = ds.Tables(0).DefaultView
        Catch ex As SqlException
        End Try
    End Sub

    'Click sobre el 'Button4': 'DataGrid1' toma los datos de la tabla 'Empleados' de 'dsUpdate',
    'que ha sido primero creada, y luego rellenada por 'daUpdate'.
    Private Sub update0(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true")
        dsUpdate = New DataSet
        'Se añade a 'dsUpdate' una tabla llamada 'Empleados'.
        dsUpdate.Tables.Add("Empleados")
        daUpdate = New SqlDataAdapter
        Dim cm As New SqlCommand("Select * From Employees", cn)
        daUpdate.SelectCommand = cm

        'Llenado
        Try
            daUpdate.Fill(dsUpdate, "Empleados")
            Me.DataGrid1.DataSource = dsUpdate.Tables("Empleados").DefaultView
        Catch ex As SqlException
            MsgBox(ex.Message)
        End Try
    End Sub

    'Método que salta al pinchar en 'Button9'. Se pretende mostrar:
    '   Si ha habido cambios en un 'DataSet'.
    '   De ser así, ¿qué tipo de cambios? -¿fila añadida, eliminada o modificada?.
    '   Una tabla con las filas retocadas.
    Private Sub update1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button9.Click
        'Detectemos qué cambios ha habido (para hacerlo bien, necesitaríamos una estructura 
        ''Select Case').
        'Dim bo As Boolean
        'If dsUpdate.HasChanges Then
        '    ¿Filas nuevas?
        '    bo = dsUpdate.HasChanges(DataRowState.Added)
        '    ¿Filas borradas?
        '    bo = dsUpdate.HasChanges(DataRowState.Deleted)
        '    ¿Filas modificadas?
        '    bo = dsUpdate.HasChanges(DataRowState.Modified)
        'End If

        'Veamos filas retocadas en el 'DataGrid2'.
        Dim dt As DataTable = dsUpdate.Tables("Empleados").GetChanges(DataRowState.Modified)
        If dt.Rows.Count > 0 Then
            Me.DataGrid2.DataSource = dt.DefaultView
        End If
    End Sub

    'En esta 'sub' se muestra cómo cambiar la base de datos de la conexión, 
    'cómo traer más de una tabla -utilizando una consulta múltiple-, 
    'y mostrar en el 'DataGrid' una sola de las tablas del 'DataSet'.
    Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true")
        cn.Open()
        'Cambiamos la base de datos a la que apuntaba la conexión.
        cn.ChangeDatabase("Pubs")
        'La consulta deberá traer tres tablas de resultados.
        Dim sql As String = "SELECT * FROM Publishers;SELECT * FROM Titles;SELECT * FROM authors"
        Dim da As New SqlDataAdapter(sql, cn)

        'Se añade una tabla sin nombre al 'DataSet'.
        Dim ds As New DataSet
        ds.Tables.Add("")

        With da
            .TableMappings.Add("Publishers", "DataPublishers")
            .ColumnMappings.Add("pub_id", "ID")
            .ColumnMappings.Add("pub_name", "Name")
        End With
        ''ds' toma el mismo esquema que el de 'da' -recordemos que éste almacena tres tablas
        'de resultados.
        da.FillSchema(ds, SchemaType.Source, "Publishers")
        'Se pone nombre a las otras 2 tablas de 'ds'.
        ds.Tables(1).TableName = "Titles"
        ds.Tables(2).TableName = "Authors"

        DataGrid1.DataSource = ds.Tables("Authors")
    End Sub
End Class



Intro XML: De 'DataSet's y de cómo éstos leen y escriben '.xml's y '.xsd's

Imports System.Data
Imports System.Xml
Imports System.IO

Public Class Form1 : Inherits System.Windows.Forms.Form
    Dim dsClase As DataSet

#Region " Código generado por el Diseñador "
    Public Sub New()
        MyBase.New()
        'Se inicializan los componentes creados con el 'Diseñador'.
        InitializeComponent()
    End Sub

    ''Dispose' se sobrecarga para eliminar los componentes en la lista. 
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Contenedor para los componentes.
    Private components As System.ComponentModel.IContainer
    'Código del 'Diseñador'; no tocar con el 'Editor de código'.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents SqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter
    Friend WithEvents SqlSelectCommand1 As System.Data.SqlClient.SqlCommand
    Friend WithEvents SqlConnection1 As System.Data.SqlClient.SqlConnection
    Friend WithEvents Button2 As System.Windows.Forms.Button
    Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid
    Friend WithEvents Button3 As System.Windows.Forms.Button
    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents Button4 As System.Windows.Forms.Button
    Friend WithEvents Button5 As System.Windows.Forms.Button
	
    'Método que inicializa los componentes creados con el 'Diseñador'.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.SqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter
        Me.SqlSelectCommand1 = New System.Data.SqlClient.SqlCommand
        Me.SqlConnection1 = New System.Data.SqlClient.SqlConnection
        Me.Button2 = New System.Windows.Forms.Button
        Me.DataGrid1 = New System.Windows.Forms.DataGrid
        Me.Button3 = New System.Windows.Forms.Button
        Me.TextBox1 = New System.Windows.Forms.TextBox
        Me.Button4 = New System.Windows.Forms.Button
        Me.Button5 = New System.Windows.Forms.Button
        CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        'Button1
        Me.Button1.Location = New System.Drawing.Point(24, 24)
        Me.Button1.Name = "Button1"
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Intro"
        'SqlDataAdapter1
        Me.SqlDataAdapter1.SelectCommand = Me.SqlSelectCommand1
        Me.SqlDataAdapter1.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "authors", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("au_id", "au_id"), New System.Data.Common.DataColumnMapping("au_lname", "au_lname"), New System.Data.Common.DataColumnMapping("au_fname", "au_fname"), New System.Data.Common.DataColumnMapping("phone", "phone"), New System.Data.Common.DataColumnMapping("address", "address"), New System.Data.Common.DataColumnMapping("city", "city"), New System.Data.Common.DataColumnMapping("state", "state"), New System.Data.Common.DataColumnMapping("zip", "zip"), New System.Data.Common.DataColumnMapping("contract", "contract")})})
        'SqlSelectCommand1
        Me.SqlSelectCommand1.CommandText = "SELECT au_id, au_lname, au_fname, phone, address, city, state, zip, contract FROM" & _
        " authors"
        Me.SqlSelectCommand1.Connection = Me.SqlConnection1
        'SqlConnection1
        Me.SqlConnection1.ConnectionString = "workstation id=RAUL;packet size=4096;user id=sa;data source=localhost;persist sec" & _
        "urity info=True;initial catalog=pubs;password="
        'Button2
        Me.Button2.Location = New System.Drawing.Point(24, 56)
        Me.Button2.Name = "Button2"
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "Metadata"
        'DataGrid1
        Me.DataGrid1.DataMember = ""
        Me.DataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText
        Me.DataGrid1.Location = New System.Drawing.Point(392, 40)
        Me.DataGrid1.Name = "DataGrid1"
        Me.DataGrid1.Size = New System.Drawing.Size(312, 240)
        Me.DataGrid1.TabIndex = 2
        'Button3
        Me.Button3.Location = New System.Drawing.Point(0, 96)
        Me.Button3.Name = "Button3"
        Me.Button3.Size = New System.Drawing.Size(96, 40)
        Me.Button3.TabIndex = 3
        Me.Button3.Text = "Grabar XMLSchema"
        'TextBox1
        Me.TextBox1.Location = New System.Drawing.Point(120, 16)
        Me.TextBox1.Multiline = True
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both
        Me.TextBox1.Size = New System.Drawing.Size(256, 264)
        Me.TextBox1.TabIndex = 4
        Me.TextBox1.Text = ""
        'Button4
        Me.Button4.Location = New System.Drawing.Point(0, 144)
        Me.Button4.Name = "Button4"
        Me.Button4.Size = New System.Drawing.Size(96, 24)
        Me.Button4.TabIndex = 5
        Me.Button4.Text = "Grabar XMData"
        'Button5
        Me.Button5.Location = New System.Drawing.Point(0, 168)
        Me.Button5.Name = "Button5"
        Me.Button5.Size = New System.Drawing.Size(112, 24)
        Me.Button5.TabIndex = 6
        Me.Button5.Text = "Grabar DiffGram-1"
        'Form1
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.AutoScroll = True
        Me.ClientSize = New System.Drawing.Size(736, 357)
        Me.Controls.Add(Me.Button5)
        Me.Controls.Add(Me.Button4)
        Me.Controls.Add(Me.TextBox1)
        Me.Controls.Add(Me.Button3)
        Me.Controls.Add(Me.DataGrid1)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "XML 1"
        CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)
    End Sub
#End Region

    'Responde al pulsar sobre 'Button1'. Se demuestra cómo inicializar un 'DataSet' de
    'tres formas distintas.
    Private Sub intro(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'Cuando se crea un 'DataSet', carece de estructura alguna.
        Dim ds As New DataSet
        'Dicha estructura se puede añadir a mano -ponemos una tabla, y a ésta una columna.
        ds.Tables.Add("Tabla1")
        ds.Tables("Tabla1").Columns.Add("Columna1")

        'Pero además se puede obtener vía un XSD schema.
        '   XSD schema es un documento que describe la estructura de un documento XML 
        '   y sus constraints, relaciones, claves, tipos de datos de cada elemento...
        Dim dsx As DataSet
        Try
            dsx = New DataSet
            ''..\' hace referencia al directorio superior del directorio base;
            'se pueden ir subiendo directorios siguiendo este patrón: "..\\..\\" etcétera.
            dsx.ReadXmlSchema("..\\XSDschema.xsd")
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

        'En lugar de leer directamente del fichero, podemos leer de un 'Stream' -un flujo de datos.
        '   Un Web service, o aplicación ASP no nos pasará un fichero; deberá ser un 'stream'.
        Dim dsx2 As DataSet
        Dim reader As StreamReader
        Try
            dsx2 = New DataSet
            reader = New StreamReader("..\\XSDschema.xsd")
            dsx2.ReadXmlSchema(reader)
        Catch ex As Exception
            MsgBox(ex.Message)
        Finally
            If Not reader Is Nothing Then
                reader.Close()
            End If
        End Try
    End Sub

    'Esta sub, que salta al 'clickar' sobre 'Button2', muestra cómo se rellena un 'DataSet'
    'a partir de un fichero '.xml', atendiendo al 'modo de lectura XML'.
    Private Sub metadata(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'Propiedades del 'DataSet' para obtener info:
        '
        'Tables  
        '   Permite referenciar la DataTableCollection de un DataSet. 
        'Relations  
        '   Permite referenciar la DataRelationCollection de un DataSet. 
        'Tables.Count  
        '   Devuelve el número de tablas en un DataSet. 
        'Tables(indice).TableName  
        '   Devuelve el nombre de la tabla en el índice especificado del DataTableCollection. 
        'Tables(nombre | indice).Columns(indiceCol)  
        '   Permite referenciar la DataColumnCollection de la columna indicada con 'indiceCol'. 
        'Tables(indice).Columns(indiceCol).ColumnName  
        '   Devuelve el nombre de la columna indicada con 'indiceCol'. 
        'Tables(indice).Columns(indiceCol).DataType  
        '   Devuelve el tipo de datos de la columna indicada con 'indiceCol'. 
        'Tables(indice).Columns.Count  
        '   Devuelve el número de columnas en la tabla. 

        'Obtenemos el 'DataSet' a partir de un fichero '.xsd' -pero sólo copiamos los datos;
        'el esquema lo obviamos.
        Dim dsx As DataSet
        Try
            dsx = New DataSet
            dsx.ReadXml("..\\XSDschema.xsd", XmlReadMode.IgnoreSchema)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

        'Aunque no tenga esquema, podemos conocer propiedades del 'DataSet'.
        With dsx
            Dim i As Int32 = .Tables.Count()
            'Dim n As String = .Tables(0).TableName    'ojo, puede volver una cadena 'null'.
        End With

        'Parámetros 'XMLReadMode' que podemos pasar al método 'readXML()', y sus consecuencias:
        Try
            'XmlReadMode.IgnoreSchema:
            '   No lee el 'inline Schema', pero sí los datos del input.
            '   Añade las tablas sólo si coinciden con la estructura del DS.
            'dsx.ReadXml("..\\XSDschema.xsd", XmlReadMode.IgnoreSchema)
            '
            'XmlReadMode.ReadSchema: Lee el schema (si lo hay), y luego carga los datos.
            '   Si el DS ya tiene un schema, añade las nuevas tablas.
            '   Si el DS ya tiene un schema, y no hay tablas nuevas, error.
            '   Si el DS no tiene schema, y no hay inline schema, no se lee nada
            'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.ReadSchema)
            '
            'XmlReadMode.InferSchema:
            '   No lee el inline schema, más bien lo infiere de leer los datos XML.
            '   Si el DS ya tiene un schema, el nuevo es añadido.
            'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema)
            '
            'XmlReadMode.DiffGram:
            '   Lee un DiffGram y añade los datos al DS.
            'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.DiffGram)
            '
            'XmlReadMode.Fragment:
            '   Añade datos a un schema ya existente en el DS (SQL).
            'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.Fragment)
            '
            'XmlReadMode.Auto: Al examinar el fichero XML, decide lo que cree más apropiado:
            '   Si el DS tiene un schema o el archivo tiene un inline schema, ejecuta 'ReadSchema'.
            '   Si DS no tiene schema y tampoco el archivo, se usa 'InferSchema'.
            'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.Auto)
            'Por rendimiento, evitar Auto.

            'Si probamos esto...
            dsx = New DataSet
            dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.ReadSchema)
            'dsx.ReadXml("..\\Dataset1.xsd", XmlReadMode.ReadSchema)
            Dim i As Integer = dsx.Tables.Count
            Dim n As String = dsx.Tables(0).TableName
            Me.DataGrid1.DataSource = dsx
            '...no se cargaron los datos porque no había esquema en el DS.
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

        'En cambio, si lo que probamos es esto...
        'dsx = New DataSet
        'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema)
        'Dim i2 As Integer = dsx.Tables.Count
        'Dim n2 As String = dsx.Tables(0).TableName
        'Me.DataGrid1.DataSource = dsx
        '...se crea un nuevo 'schema' inferido de los datos, y éstos son cargados.
    End Sub

    'Aquí mostramos cómo convertir el 'schema' de un 'DataSet' en un fichero '.xsd'.
    'La subrutina salta al hacer click en el 'Button3'.
    Private Sub grabar(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim dsx As DataSet
	      Try
            dsx = New DataSet
            dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema)
            Me.DataGrid1.DataSource = dsx
            'El 'DataSet' -con datos y esquema- está listo y mostrándose en el 'DataGrid1'.

            'Ahora escibimos la estructura del 'DataSet' como un fichero '.xsd',
            'utilizando el método 'WriteXmlSchema()'.
            dsx.WriteXmlSchema("ficheroschema.xsd")         'Fichero en el directorio base.

            'También podemos conocer el esquema XML mediante 'GetXmlSchema()', que lo 
            'escribe en una cadena de texto.
            Dim str As String = dsx.GetXmlSchema
            Me.TextBox1.Text = str
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    'La subrutina contesta al pinchar sobre 'Button4'. 
    'Se indica cómo escribir un 'DataSet' a presión en un fichero '.xml'.
    Private Sub grabardata(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim dsx As DataSet
        Try
            dsx = New DataSet
            dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema)
            Me.DataGrid1.DataSource = dsx
            'El 'DataSet' -con datos y esquema- está listo y mostrándose en el 'DataGrid1'.

            'Podemos grabar un fichero '.xml' con los datos de 'DataSet' usando 'WriteXml()'.
            dsx.WriteXml("fichero.xml")                       'Fichero en el directorio base.

            'Es posible especificar el 'modo de escritura XML' que utilizará 'WriteXml()',
            'igual que se podía indicar el modo de lectura en 'ReadXml()'.
            '
            'No se incluye el schema con los datos. Y si tampoco hay datos, no se crea fichero.
            'dsx.WriteXml("ficheroIgNoreSchema.xml", XmlWriteMode.IgnoreSchema)
            'Sólo se escribe el 'schema', sin los datos. Si no hay esquema, no se crea fichero.
            'dsx.WriteXml("ficheroWriteSchema.xml", XmlWriteMode.WriteSchema)
            'Contiene los valores originales y actuales de la información.
            'dsx.WriteXml("ficheroDiffGram.xml", XmlWriteMode.DiffGram)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    'Muestra cómo grabar un 'Dataset' a un fichero '.xml' en modo 'DiffGram': de esta forma 
    'se guardan los valores originales del 'DataSet', y los nuevos.
    'Por cierto, la sub saltará al accionar el 'Button5'.
    Private Sub grabardiff(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Try
            'Llenamos un 'DataSet' con los datos de una BD.
            Dim cn As New SqlClient.SqlConnection("data source=localhost;integrated security=True;initial catalog=pubs;")
            cn.Open()
            Dim da As New SqlClient.SqlDataAdapter("Select * from authors", cn)
            Dim ds As New DataSet
            da.Fill(ds, "Autores")

            'Vamos a hacer unos cambios: 
            '   Borramos la fila 0, 
            '   y cambiamos el nombre y apellido del registro de la fila 1.
            With ds.Tables("Autores")
                .Rows(0).Delete()
                .Rows(1)("au_fname") = "PEpe"
                .Rows(1)("au_lname") = "gotera"
            End With

            'Pasamos el 'DataSet' al 'DataGrid1', e intentamos escribir el 'DiffGram'.
            Me.DataGrid1.DataSource = ds
            ds.WriteXml("XMLSoloDiferencias.xml", XmlWriteMode.DiffGram)
        Catch ex As Exception
            Console.WriteLine("Excep: " & e.ToString())
        End Try
    End Sub
End Class


Remoting: Accedediendo a objetos remotos desde una aplicación local


La aplicación del cliente no se puede ejecutar si el servicio remoto no está corriendo.

MarshalByRefObject es la clase base de los objetos que se comunican a través de los límites de los dominios de aplicación que utilizan un proxy para intercambiar mensajes. 
Proxy: Servidor 'intermediario' que se utiliza para hacer consultas a un servidor en lugar de conectar el equipo directamente a éste. Los proxys se utilizan para mejorar la seguridad del servidor, y tener más control administrativo.


El objeto remoto:

Namespace ServiciosRemotos
'La clase 'HelloWorld' debe heredar de 'MarshallByRefObject'.
Public Class HelloWorld : Inherits MarshalByRefObject
    'Función que devuelve un mensajito.
    Public Function Display () As String
        Return "Hola, soy un objeto remoto que viene del servidor."
    End Function
End Class
End Namespace


El servidor:

Imports ServiciosRemotos
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels.Tcp
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Form1 : Inherits System.Windows.Forms.Form

#Region " Código generado por el Diseñador "
    Public Sub New()
        MyBase.New()
        'Se inicializan los componentes creados con el 'Diseñador'.
        InitializeComponent()
    End Sub

    ''Dispose' se sobrecarga para eliminar los componentes en la lista. 
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Contenedor para los componentes.
    Private components As System.ComponentModel.IContainer
    'Método que inicializa el formulario.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        'Form1
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 273)
        Me.Name = "Form1"
        Me.Text = "Form1"
    End Sub
#End Region

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Se crea un canal para comunicarnos con el servicio a publicar.
        Dim channel As TcpServerChannel = New TcpServerChannel(9932)
        ChannelServices.RegisterChannel(channel)

        'Registramos 'HelloWorld' como un tipo conocido en el servicio: así se hace accesible al cliente.
        'El modo de acceso a este objeto se definie como 'SingleCall' - Todos los mensajes entrantes 
        'son atendidos por una nueva instancia del objeto. Esto no sale a cuenta, por cuestión
        'de rendimiento, cuando va a haber muchos clientes accediendo al objeto.
        RemotingConfiguration.RegisterWellKnownServiceType(GetType(HelloWorld), "HelloWorld", WellKnownObjectMode.SingleCall)
    End Sub
End Class


El cliente:

Imports ServiciosRemotos
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels.Tcp
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Form1 : Inherits System.Windows.Forms.Form

#Region " Código generado por el Diseñador "
    Public Sub New()
        MyBase.New()
        'Se inicializan los componentes creados con el ‘Diseñador'.
        InitializeComponent()
    End Sub

    ''Dispose' se sobrecarga para eliminar los componentes en la lista. 
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Contenedor para los componentes.
    Private components As System.ComponentModel.IContainer
    'Método que inicializa el formulario.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        'Form1
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 273)
        Me.Name = "Form1"
        Me.Text = "Form1"
    End Sub
#End Region

    'Al ejecutarse la aplicación en el equipo del cliente, ...
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ChannelServices.RegisterChannel(New TcpClientChannel)
        '...'Activator.GetObject()' crea un proxy que administra el objeto 'HelloWorld' en el 
        'servidor, de tal forma que 'objRemoto' será un puntero a ese objeto 'HelloWorld' 
        'en el servidor.
        Dim objRemoto As HelloWorld = CType(Activator.GetObject(GetType(HelloWorld), "tcp://192.168.0.64:9932/HelloWorld"), HelloWorld)
        'Ya se puede utilizar 'objRemoto' como si estuviera en RAM, aunque realmente no sea así.
        'El objeto remoto determina el texto de título del formulario.
        Me.Text = objRemoto.Display
    End Sub
End Class

¿Comentarios, sugerencias?: llopsite.at.yahoo.es | © 2005-07 Albert Lobo

Última actualización: 18-Feb-2007

Hosted by www.Geocities.ws

1