none
actualizar dataset tipado con varias tablas .NET

    Question

  • Holaa!

    Tengo una duda "existencial"

    Estoy programando en visual basic studio .Net, y quiero hacer una gestion de clientes, tengo una tabla clientes y asociada a esta tabla otras tablas como tipo_Iva, Banco, Forma_Pago y alguna más. Entonces en la pantalla de gestión cliente quiero poner todos los campos de la tabla de cliente y se tienen que mostrar también algunos campos de sus tablas relacionadas, como nombre_banco, Nombre_Forma_de_pago, que pertenecen a las otras tablas.

    Entonces estoy pensando en dos posibilidades, la que hasta ahora me sale, pero no se si es la forma más elegante de hacerla, que es crear un DataSet tipado por cada tabla, entonces tengo en el formulario tengo que tener todos los dataset de las tablas aunque no quiera modificar los datos de las tablas relacionadas, en este caso tengo muchos dataset y por cada dataset tengo que hacer fill según el código del cliente, en este caso el dataset de cliente crea automáticamente el comando update y puedo actualizarlo sin problema.

     

    El otro modo es hacer un dataset con una consulta en la que capturo ya todos los valores de cliente y los valores asociados que me intersan de las otras tablas, en este caso solo tengo un dataset tipado con varias tablas dentro, pero el problema es que no me crea el comando update automáticamente, y si se lo meto "a pelo" me da un error en ejecución el update que dice " error de parametro _?24 no tiene valor predeterminado".

    Entonces la duda es cual es mejor sistema? es correcta la segunda opción? como se tendría que crear el comando update sólo para la tabla cliente?

    Espero vuestra ayuda.

    Gracias.

    • Moved by Enrique M. MontejoMVP Tuesday, April 21, 2015 2:38 PM Pregunta relacionada con el acceso a datos.
    Thursday, October 21, 2010 10:25 AM

All replies

  • hola

    Entonces la duda es cual es mejor sistema? es correcta la segunda opción? como se tendría que crear el comando update sólo para la tabla cliente?

    lo que sucede es que al utilizar una query que imagino incluye JOIN entre varias tablas no podras actualizarla ya que un comando UPDATE o INSERT solo impactan contra una tabla a la vez, es logico que no genere estos comandos

    para que el DataSet tipado genere automaticamente esto un datatable solo puede referenciar una tabla, como lo tenias al principio

    lo que podrias hacer son dos DataSet, uno que sea de solo lectura la cargar la info del formulario, y otro para la actualizacion

    solo que el volcado de los datos de la pantalla a este segundo dataset sera manual, o mejor dicho deberas programarlo explciitamente, buscando el registro del cliente he impactando los cambios del usuario, o si se agrega un nuevo cliente deberas inser el registro nuevo en el dataset y al final hacer el Update(), por ahi no es tan automatico pero de esta forma tendrias un medio para recuperar la informacion completa y otro para actualizarla

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Thursday, October 21, 2010 11:35 AM
  • Gracias por responder!

    Y no puedo hacer un update sólo de la tabla Clientes aunque tenga el dataset con varias tablas utilizando Join?

    porque aunque no me lo ha creado automáticamente, le he añadido copiando en el editor la misma cadena de update que me había creado automáticamente otro dataset que tenía solo de la tabla clientes. En ese caso al principio me deba un error a la hora de hacer Update que era "error parametro_24 no tiene valor predeterminado" esto lo soluciné comparando los dos dataset, el de clientes solo y el de clientes con varias tablas, me di cuenta que unos parámetros había que poner null por defecto , los puse todos y se solucionó, pero ahora me da otro error, me dice "error de concurrencia que modifico 0 de los 1 registros" y no actualiza, por eso me plantee si estaba intentando hacer una cosa muy rara o imposible. Se te ocurre como solucionarlo?

    Tu solución me parece acertada, pero en ese caso, que es mejor tu solucion o tener un dataset por cada tabla, y hacer un fill de cada una de ellas según el código del cliente?

    Yo quería evitar tener 5 dataset y hacer fill de cada una de ellas, me parecía más elegante tener todo en un dataset, y luego sólo actualizar los campos del cliente, porque los demás solo son informativos.

    El Código de update que meto es el mismo que me genera el dataset clientes:

    UPDATE  CLIENTE
    SET       CODCLI = ?, NOMBRE = ?, NOMBRECOM = ?, DNI = ?, CP = ?, DIRECCION = ?, TFNO = ?, MOVIL = ?, EMAIL = ?, OBS = ?, FP = ?, CONTACTO = ?, 
               DIAPAGO1 = ?, DIAPAGO2 = ?, DIAPAGO3 = ?, DTO = ?, CODBANCO = ?, NUMCUENTA = ?, DIRECBANCO = ?, FAX = ?, FAMILIA = ?, IVA = ?
    WHERE   (CODCLI = ?) AND (? = 1 AND NOMBRE IS NULL OR
               NOMBRE = ?) AND (? = 1 AND NOMBRECOM IS NULL OR
               NOMBRECOM = ?) AND (? = 1 AND DNI IS NULL OR
               DNI = ?) AND (? = 1 AND CP IS NULL OR
               CP = ?) AND (? = 1 AND DIRECCION IS NULL OR
               DIRECCION = ?) AND (? = 1 AND TFNO IS NULL OR
               TFNO = ?) AND (? = 1 AND MOVIL IS NULL OR
               MOVIL = ?) AND (? = 1 AND EMAIL IS NULL OR
               EMAIL = ?) AND (? = 1 AND FP IS NULL OR
               FP = ?) AND (? = 1 AND CONTACTO IS NULL OR
               CONTACTO = ?) AND (? = 1 AND DIAPAGO1 IS NULL OR
               DIAPAGO1 = ?) AND (? = 1 AND DIAPAGO2 IS NULL OR
               DIAPAGO2 = ?) AND (? = 1 AND DIAPAGO3 IS NULL OR
               DIAPAGO3 = ?) AND (? = 1 AND DTO IS NULL OR
               DTO = ?) AND (? = 1 AND CODBANCO IS NULL OR
               CODBANCO = ?) AND (? = 1 AND NUMCUENTA IS NULL OR
               NUMCUENTA = ?) AND (? = 1 AND DIRECBANCO IS NULL OR
               DIRECBANCO = ?) AND (? = 1 AND FAX IS NULL OR
               FAX = ?) AND (? = 1 AND FAMILIA IS NULL OR
               FAMILIA = ?) AND (? = 1 AND IVA IS NULL OR
               IVA = ?)

    Puedes ayudarme?

    Gracias.

    Friday, October 22, 2010 7:45 AM
  • Hola, ya que me rompia la cabeza para encontrar un metodo similar a Resync del ADO 2.5 de antaño, les voy a compartir este codigo de un formulario de empleados:

    El escenario es una base de datos de access con 2 tablas: empleados y areas (u oficina/dependencia a las que pertenece este empleado), hay una consulta creada dentro de Accees que se llama [Consulta de Empleados] que me recupera la información del empleado más el nombre del area en que labora (que se encuentra en la tabla areas, por consiguiente es una consulta de 2 tablas unidas por JOIN: Empleados.AreaID = Areas.AreaID)

    Debo decirte que el asistente para generar TableAdapter no te va a generar codigo para INSERT, ni para UPDATE, ni para DELETE, por lo que tu mismo lo agregaras en sus propiedades por ejemplo para INSERT seria INSERT INTO Empleados (cNombreEmpleado, AreaID) Values (?, ?), ojo, solo referencias a la tabla principal, en este caso Empleados, el EmpleadoID es un autonumerico por eso no lo coloco ya que al momento de insertar la base de datos generará uno (y la rompedera de cabeza será como recuperarlo y mostrarlo, pero no te preocupes porque más adelante te lo explico), para UPDATE y DELETE ya tu mismo eres.

    A continuación el código, el formulario es generado automaticamente al arrastrar desde el origen de datos la consulta, que me agrega una barra de navegación y un DBGridView que me muestra la consulta [Consulta de Empleado] (que tiene el campo cNombreArea de la tabla Areas).

    Lo importante que este código funciona de la siguiente manera: al momento de insertar un nuevo registro, se obtiene el nuevo ID de la tabla empleado y automaticamente el valor de cNombreArea de la tabla Areas que se verá reflejado en el DataGridview del formulario.

    Analizenlo y disfrutenlo ya que todo esta alrededor del evento OnRowUpdate (ahh.. y para ponerlo mejor va con una transacción de ejemplo)

    Imports System.Data
    Imports System.Data.OleDb
    
    Public Class frmEmpleados
      Private Connection As OleDbConnection
      Private Transaction As OleDbTransaction
    
      Private Sub ConsultaEmpleadosBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConsultaEmpleadosBindingNavigatorSaveItem.Click
        Me.Validate()
        Me.ConsultaEmpleadosBindingSource.EndEdit()
    
        If ValidateForm() Then
          If SaveRecordChanges() Then
            ' ..
          End If
        End If
      End Sub
    
      Private Function ValidateForm() As Boolean
        ValidateForm = True
      End Function
    
      Private Function SaveRecordChanges() As Boolean
        ' Iniciamos una conexión compartida
        Connection = Me.ConsultaEmpleadosTableAdapter.Connection
        ' Abrimos la conexión
        Connection.Open()
        ' Iniciamos una transacción
        Transaction = Connection.BeginTransaction()
        ' Asignamos la transacción a los TableAdapters
        With Me.ConsultaEmpleadosTableAdapter.Adapter
          .InsertCommand.Transaction = Transaction
          .UpdateCommand.Transaction = Transaction
          .DeleteCommand.Transaction = Transaction
        End With
        ' Intentamos la actualización en la base de datos
        Try      
          ' Actualizamos el origen de datos con las modificaciones
          Me.ConsultaEmpleadosTableAdapter.Update(Me.DbSysMainDataSet.ConsultaEmpleados)      
          ' Confirmar la transacción
          Transaction.Commit()
          ' Se puede omitir
          Me.DbSysMainDataSet.ConsultaEmpleados.AcceptChanges()
          ' Exito
          SaveRecordChanges = True
        Catch ex As DBConcurrencyException
          ' Si hay error, desahacemos lo que se haya hecho
          Transaction.Rollback()
          ' Obtener los datos actualizados desde la base de datos
          If MessageBox.Show("El registro ya no es accesible en el origen de datos, es posible que un usuario de la red haya eliminado el registro" & vbCrLf & vbCrLf & "¿Desea obtener los datos actuales desde la base de datos?", Me.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = Windows.Forms.DialogResult.Yes Then
            Me.DbSysMainDataSet.ConsultaEmpleados.RejectChanges()
            Me.ConsultaEmpleadosTableAdapter.Fill(Me.DbSysMainDataSet.ConsultaEmpleados)
          End If
          ' Fracaso
          SaveRecordChanges = False
        Catch ex As Exception
          ' Si hay error, desahacemos lo que se haya hecho
          Transaction.Rollback()
          ' Mostrar error y preguntar si se descartan las modificaciones
          If MessageBox.Show(ex.Message & vbCrLf & vbCrLf & "¿Desea descartar todas las modificaciones a sus valores originales?", Me.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = Windows.Forms.DialogResult.Yes Then
            Me.DbSysMainDataSet.ConsultaEmpleados.RejectChanges()
          End If
          ' Fracaso
          SaveRecordChanges = False
        End Try
        ' Cerramos la conexión
        Connection.Close()
      End Function
    
      Private Sub OnRowUpdated(ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs)
        ' Las filas eliminadas se ignoran
    If e.StatementType = StatementType.Delete Then Exit Sub ' Recuperar el ID de los nuevos registros insertados If e.StatementType = StatementType.Insert Then Dim GetIDCommand As New OleDbCommand("SELECT @@IDENTITY", Connection, Transaction) e.Row("EmpleadoID") = CInt(GetIDCommand.ExecuteScalar()) End If ' Recuperar los campos foraneos de la consulta de combinación Dim ResyncCommand As New OleDbCommand("SELECT * FROM [Consulta de Empleados] WHERE EmpleadoID = " & e.Row("EmpleadoID").ToString, Connection, Transaction) Dim ResyncDataReader As OleDbDataReader = ResyncCommand.ExecuteReader() While ResyncDataReader.Read() e.Row("cNombreArea") = ResyncDataReader("cNombreArea") End While ResyncDataReader.Close() ' Las filas no deben modificar su RowState e.Status = UpdateStatus.SkipCurrentRow End Sub Private Sub frmEmpleados_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed ' Liberar el manejador de eventos que lanza OnRowUpdated RemoveHandler Me.ConsultaEmpleadosTableAdapter.Adapter.RowUpdated, New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated) End Sub Private Sub frmEmpleados_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Manejador para el evento OnRowUpdate que se desencadenará al momento de actualizar un registro AddHandler Me.ConsultaEmpleadosTableAdapter.Adapter.RowUpdated, New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated) 'TODO: esta línea de código carga datos en la tabla 'DbSysMainDataSet.ConsultaEmpleados' Puede moverla o quitarla según sea necesario. Me.ConsultaEmpleadosTableAdapter.Fill(Me.DbSysMainDataSet.ConsultaEmpleados) End Sub End Class


    Wednesday, April 15, 2015 9:55 PM
  • Hola:
    En el siguiente ejemplo, se usa 1 tabla llamada APLICA_PREST con la siguiente estructura

    CREATE TABLE [APLICA_PREST] (
     [APLICACION] [tinyint] NOT NULL ,
     [PRESTACION] [smallint] NOT NULL ,
     [DESCRIPCION] [varchar] (75) COLLATE Modern_Spanish_CI_AS NOT NULL ,
     CONSTRAINT [PK_APLICA_PREST] PRIMARY KEY  CLUSTERED
     (
      [APLICACION],
      [PRESTACION]
     )  ON [PRIMARY] ,
     CONSTRAINT [FK_APLICA_PREST_APLICACION] FOREIGN KEY
     (
      [APLICACION]
     ) REFERENCES [APLICACION] (
      [ID_APLICACION]
     ),
     CONSTRAINT [FK_APLICA_PREST_PRESTACION] FOREIGN KEY
     (
      [PRESTACION]
     ) REFERENCES [PRESTACION] (
      [ID_PRESTACION]
     )
    ) ON [PRIMARY]

    Como se puede ver, esta relacionada con las tablas APLICACION y PRESTACION
    Para mostrar los datos en el Grid, tienes que hacer una consulta como esta

    Select APLICA_PREST.APLICACION, APLICA_PREST.PRESTACION, APLICA_PREST.DESCRIPCION, APLICACION.DESCRIPCION As DES_APLICACION, PRESTACION.DESCRIPCION As DES_PRESTACION 
    From APLICA_PREST
    Inner Join APLICACION On APLICACION.ID_APLICACION=APLICA_PREST.APLICACION
    Inner Join PRESTACION On PRESTACION.ID_PRESTACION=APLICA_PREST.PRESTACION
    Order By APLICA_PREST.APLICACION, APLICA_PREST.PRESTACION

    El resultado de esta consulta lo cargas en 1 DataTable y como fuente de datos del Grid, pones ese DataTable

    Para añadir 1 registro a la tabla APLICA_PREST, tienes que hacer una consulta como esta

    Insert Into APLICA_PREST (APLICACION, PRESTACION, DESCRIPCION) Values (@Aplicacion, @Prestacion, @Descripcion)

    Para modificar 1 registro a la tabla APLICA_PREST, tienes que hacer una consulta como esta

    Update APLICA_PREST Set DESCRIPCION=@Descripcion Where APLICACION=@Aplicacion And PRESTACION=@Prestacion


    Espero que se entienda

    Un saludo desde Bilbo
    Carlos

    • Proposed as answer by Karen Malagón Thursday, April 23, 2015 8:43 PM
    Thursday, April 16, 2015 7:27 AM