none
¿Como guardar en formulario maestro-detalle?

    Question

  • Hola, el problema que tengo es a la hora de guardar los datos de un formulario maestro-detalle en vb.net 2010; el formulario me muestra correctamente los registros maestros y sus respectivos detalles. Pero cuando inserto un nuevo registro solo me guarda el maestro y no el detalle. Como dato adicional las relaciones de las tablas no están implementadas en la bd solo en el dataset.

    Este es el código que estuve probando:

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            'TODO: esta línea de código carga datos en la tabla 'BdSqlDataSet.Maestro' Puede moverla o quitarla según sea necesario.

            Me.MaestroTableAdapter.Fill(Me.BdSqlDataSet.Maestro)

            'TODO: esta línea de código carga datos en la tabla 'BdSqlDataSet.Detalle' Puede moverla o quitarla según sea necesario.

            Me.DetalleTableAdapter.Fill(Me.BdSqlDataSet.Detalle)

        End Sub

     

        Private Sub Nuevo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Nuevo.Click

            Me.MaestroBindingSource.AddNew()

            Me.DetalleBindingSource.AddNew()

        End Sub

     

        Private Sub Guardar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Guardar.Click

            Me.MaestroBindingSource.EndEdit()

            Me.DetalleBindingSource.EndEdit()

            Me.MaestroTableAdapter.Update(Me.BdSqlDataSet)

            Me.DetalleTableAdapter.Update(Me.BdSqlDataSet)

        End Sub

    Si alguien me pueda dar alguna pista concreta de cómo puedo hacer que funcione el formulario. le agradezco.

     

    Monday, August 08, 2011 2:21 PM

Answers

  • > Luego cuando pongo nuevo me coloca el número -1 en el campo que es auto numérico

    ¿El campo PEID está definido como Autonumérico o Identity? Si la respuesta es afirmativa, tienes que configurar las propiedades «AutoIncrementSeed» y «AutoIncrementStep» del objeto DataColumn que actúa de campo autonumérico (PEID).

    Para ello, añade al evento Load del formulario lo siguiente:

        ' Referenciamos la columna autonumérica
        '
        Dim dc As DataColumn = Me.BdSqlDataSet.Maestro.Columns("PEID")
    
        If (dc.AutoIncrement) Then
          ' Valor inicial del campo
          dc.AutoIncrementSeed = ObtenerUltimoAutonumerico() + 1
    
          ' Valor del incremento del campo
          dc.AutoIncrementStep = +1
        End If
    
        ' Y después rellenamos los objetos DataTable
        '
        Me.MaestroTableAdapter.Fill(Me.BdSqlDataSet.Maestro)
    
        Me.DetalleTableAdapter.Fill(Me.BdSqlDataSet.Detalle)
    

    Como observarás, tendrás que llamar a una función (ObtenerUltimoAutonumerico) que te devuelva el último valor autonumérico existente en la tabla, al cual le tendrás que sumar una unidad, o aquel valor que le hayas asignado a la propiedad AutoIncrementStep del campo, una función que te devuelva el resultado de ejecutar la siguiente consulta SQL de selección:
     
        SELECT TOP 1 PEID
        FROM NombreTablaMaestro
        ORDER BY PEID DESC

    Me imagino que sabrás construir la función 'ObtenerUltimoAutonumerico' para ejecutar la consulta SQL indicada y obtener el último valor que tenga el campo PEID.

    Es necesario obtener el último valor autonumérico existente en la tabla física, para que los datos estén sincronizados con los existentes en tu DataSet "tipado".


    Enrique Martínez
      [MS MVP - VB]

    • Marked as answer by Claudio Selva Monday, August 08, 2011 11:55 PM
    Monday, August 08, 2011 10:12 PM

All replies

  • Hola:

    En principio no observo nada raro para que no puedes actualizar los registros de la tabla Detalle. ¿Obtienes algún error? En la base de datos, ¿las tablas tienen establecida su correspondiente clave principal?

    Haz doble clic sobre la relación, y comprueba que sólo se haya creado la relación, tal y como aparece remarcado en amarillo en la siguiente imagen:


    Enrique Martínez
      [MS MVP - VB]

    Monday, August 08, 2011 5:48 PM
  • Antes que nada muchas gracias por responder, estuve verificando lo que me mencionas y todo bien... Pero mientras revisaba la BD me di cuenta que guarda el detalle; pero en el campo DOPEID me deja el valor -1 y por esto se rompe la relación y el formulario no me muestra nada, no sé porqué no me asigna el valor como en el campo PEID.

    Monday, August 08, 2011 7:15 PM
  • > pero en el campo DOPEID me deja el valor -1 y por esto se rompe
    > la relación y el formulario no me muestra nada, no sé porqué no
    > me asigna el valor como en el campo PEID.

    Lo siento, pero ahí ya no llego, porque no tengo ni la más remota idea del motivo que en el campo DOPEID te inserte un valor -1. ¿?

    Tú sabrás el diseño que tienen las tablas de tu base de datos, los valores por defecto que le has asignado a los distintos campos, y las relaciones existentes entre las tablas.

    Me parece a mí que más bien va a ser un problema de diseño de tus tablas que un problema de Visual Basic.

     

     


    Enrique Martínez
      [MS MVP - VB]


    Monday, August 08, 2011 7:43 PM
  • Gracias por tu respuesta, no creo que tenga que ver el diseño de las tablas, el modelo de datos ya lo tengo funcionando con VBA en Access y me tope con este problema al intentar migrar a VB.net, a lo mejor estas imágenes aclaran el panorama y por las dudas repito que las relaciones en la BD no están implementadas.

    Este es el formulario mostrando los datos, que hasta ahí estaría bien…

    Luego cuando pongo nuevo me coloca el número -1 en el campo que es auto numérico

    Y lo que sucede es que cuando guardo,  el valor de campo PEID se lo asigna la BD pero el VB no lo actualiza en el campo DOPEID. No sé si estoy cometiendo algún error de novato que sea obvio pero como antes mencione en VBA y SQL funcionaba bien.
    Monday, August 08, 2011 9:13 PM
  • > Luego cuando pongo nuevo me coloca el número -1 en el campo que es auto numérico

    ¿El campo PEID está definido como Autonumérico o Identity? Si la respuesta es afirmativa, tienes que configurar las propiedades «AutoIncrementSeed» y «AutoIncrementStep» del objeto DataColumn que actúa de campo autonumérico (PEID).

    Para ello, añade al evento Load del formulario lo siguiente:

        ' Referenciamos la columna autonumérica
        '
        Dim dc As DataColumn = Me.BdSqlDataSet.Maestro.Columns("PEID")
    
        If (dc.AutoIncrement) Then
          ' Valor inicial del campo
          dc.AutoIncrementSeed = ObtenerUltimoAutonumerico() + 1
    
          ' Valor del incremento del campo
          dc.AutoIncrementStep = +1
        End If
    
        ' Y después rellenamos los objetos DataTable
        '
        Me.MaestroTableAdapter.Fill(Me.BdSqlDataSet.Maestro)
    
        Me.DetalleTableAdapter.Fill(Me.BdSqlDataSet.Detalle)
    

    Como observarás, tendrás que llamar a una función (ObtenerUltimoAutonumerico) que te devuelva el último valor autonumérico existente en la tabla, al cual le tendrás que sumar una unidad, o aquel valor que le hayas asignado a la propiedad AutoIncrementStep del campo, una función que te devuelva el resultado de ejecutar la siguiente consulta SQL de selección:
     
        SELECT TOP 1 PEID
        FROM NombreTablaMaestro
        ORDER BY PEID DESC

    Me imagino que sabrás construir la función 'ObtenerUltimoAutonumerico' para ejecutar la consulta SQL indicada y obtener el último valor que tenga el campo PEID.

    Es necesario obtener el último valor autonumérico existente en la tabla física, para que los datos estén sincronizados con los existentes en tu DataSet "tipado".


    Enrique Martínez
      [MS MVP - VB]

    • Marked as answer by Claudio Selva Monday, August 08, 2011 11:55 PM
    Monday, August 08, 2011 10:12 PM
  • Aquí tienes una función 'ObtenerUltimoAutonumerico' para conectarte con la base física de SQL Server y recuperar el último valor del campo PEID de tu tabla.

    Fíjate que tendrás que asignarle la cadena de conexión con tu base de datos al constructor del objeto SqlConnection, referenciada en la función por la variable 'cadena_Conexion':

      Private Function ObtenerUltimoAutonumerico() As Integer
    
        Using cnn As New SqlConnection(cadena_Conexion)
    
          Try
            ' Creamos y configuramos un objeto Command 
            ' 
            Dim cmd As SqlCommand = cnn.CreateCommand()
    
            cmd.CommandText = _
              "SELECT TOP 1 PEID " & _
              "FROM NombreTablaMaestro " & _
              "ORDER BY PEID DESC"
    
            ' Abrimos la conexión 
            ' 
            cnn.Open()
    
            ' Ejecutamos la consulta
            ' 
            Dim value As Object = cmd.ExecuteScalar()
    
            Return CInt(value)
    
          Catch ex As Exception
            Return -1
    
          End Try
    
        End Using
    
      End Function
    


    Enrique Martínez
      [MS MVP - VB]

    Monday, August 08, 2011 10:23 PM
  • Bueno muchas gracias me fue de mucha ayuda, pero lo que creí es que el dataset podía manejar los campos Identity de una manera mucho mas automática ya que las relaciones están implementadas en el.

    El problema lo puedo resolver como lo propones y te agradezco mucho tu ayuda, pero es decepcionante que el vb.net no tenga una manera de obtener los valores automáticamente al momento de guardar los cambios.

    Saludos y muchas gracias nuevamente.

    Monday, August 08, 2011 10:40 PM
  • "Claudio Selva" escribió:

    > creí es que el dataset podía manejar los campos Identity de una manera
    > mucho mas automática ya que las relaciones están implementadas en el.

    Y lo hace de una manera automática, aunque si deseas que esté sincronizado con los datos de la tabla de tu base de datos física, tendrás que especificarle los parámetros de inicio, porque si no es así, comenzará por el número -1.

    Ten en cuenta que en el mundo de .NET, un objeto DataSet es el primer objeto perteneciente a la tecnología DESCONECTADA de ADO .NET, es decir, NO SE ENCUENTRA CONECTADO A NINGÚN ORIGEN DE DATOS, aunque parezca que no es así. Y si estuviera conectado, de nada hubiera servido que los ingenieros de Microsoft hubieran inventado el objeto DataSet, porque podíamos haber seguido trabajando con los objetos de la clásica biblioteca de ADO.

    > es decepcionante que el vb.net no tenga una manera de obtener los
    > valores automáticamente al momento de guardar los cambios.

    No creo que Visual Basic o C# tengan aquí la culpa. Ambos son lenguajes de programación que, por sí solos, no son capaces de establecer una conexión con un origen de datos para recabar información. Necesitan de objetos existentes en otras bibliotecas, llámense COM o .NET, para tener acceso a los datos.

    Utilizando éstas bibliotecas, es tu aplicación la que tiene que implementar algún mecanismo para inicializar un campo autonumérico existente en un objeto DataTable (el segundo objeto desconectado de ADO .NET) para obtener los valores, como es el caso de la función ObtenerUltimoAutonumerico que te acabo de presentar. :-)


    Enrique Martínez
      [MS MVP - VB]


    Tuesday, August 09, 2011 2:44 PM