none
Cómo hacer para que parezcan en un DataGridView datos de otra tabla distinta a la vinculada en dicho DataGridView RRS feed

  • Pregunta

  • Buenos días, no sé si el titulo que he puesto a mi pregunta es el que mejor refleja el problema que quiero exponer, así que a ver si consigo explicarlo de forma que se me entienda y sin extenderme demasiado. 

    Estoy con Visual Studio Express 2013 para escritorio de Windows.

    Trabajo con un DataSet tipado. Entre muchas tablas en este dataSet, tengo una tabla llamada Estudios y otra llamada Criterios, y cada una de ellas tienen los campos mas importantes que me ocupan este problema y que detallo a continuación:

    Estudios (id, ...)

    Criterios (id, DescripcionCriterio)

    Estas tablas están relacionadas entre sí mediante otra tabla llamada CriteriosEstudio, y ésta contiene sólo dos campos, idEstudio y idCriterio.

    Como dato, un estudio puede tener varios criterios.

    Cuando presento un estudio en un formulario, en éste incluyo un DataGridView donde deben aparecer todas las Descripciones de los criterios pertenecientes al estudio. La tabla que he enlazado al dataGrid, es la tabla relación CriteriosEstudio, pero claro, en esta tabla no dispongo de la Descripción del criterio, la cual está en el campo DescripcionCriterio en la tabla Criterios, y en el DataGrid sólo dispongo del campo idCriterio para mostrar. No puedo enlazar la tabla Criterios al dataGrid porque me aparecerían todos los criterios de dicha tabla, y solo quiero que aparezcan los asignados al estudio, y los asignados al estudio los tengo en la relación CriteriosEstudio. no sé si me he explicado bien.

    Quisiera saber cómo proceder en estos casos, ya que son muchos los que se me dan en toda la aplicación.

    A ver si me podéis echar una mano en este tema.

    Gracias y un saludo a todos.

     

    • Cambiado Enrique M. Montejo martes, 21 de abril de 2015 14:41 Pregunta relacionada con el acceso a datos.
    miércoles, 15 de abril de 2015 10:45

Todas las respuestas

  • Hola:
    Para el ejemplo he creado 3 tablas con las siguientes estructuras

    CREATE TABLE [CRITERIO] (
     [ID] [tinyint] NOT NULL ,
     [DESCRIPCION] [varchar] (50) COLLATE Modern_Spanish_CI_AS NOT NULL ,
     CONSTRAINT [PK_CRITERIO] PRIMARY KEY  CLUSTERED
     (
      [ID]
     )  ON [PRIMARY]
    ) ON [PRIMARY]

    CREATE TABLE [ESTUDIO] (
     [ID] [tinyint] NOT NULL ,
     [DESCRIPCION] [varchar] (50) COLLATE Modern_Spanish_CI_AS NOT NULL ,
     CONSTRAINT [PK_ESTUDIO] PRIMARY KEY  CLUSTERED
     (
      [ID]
     )  ON [PRIMARY]
    ) ON [PRIMARY]

    CREATE TABLE [CRITERIO_ESTUDIO] (
     [CRITERIO] [tinyint] NOT NULL ,
     [ESTUDIO] [tinyint] NOT NULL ,
     CONSTRAINT [PK_CRITERIO_ESTUDIO] PRIMARY KEY  CLUSTERED
     (
      [CRITERIO],
      [ESTUDIO]
     )  ON [PRIMARY] ,
     CONSTRAINT [FK_CRITERIO_ESTUDIO_CRITERIO] FOREIGN KEY
     (
      [CRITERIO]
     ) REFERENCES [CRITERIO] (
      [ID]
     ),
     CONSTRAINT [FK_CRITERIO_ESTUDIO_ESTUDIO] FOREIGN KEY
     (
      [ESTUDIO]
     ) REFERENCES [ESTUDIO] (
      [ID]
     )
    ) ON [PRIMARY]

    He insertado los siguientes registros

    Insert Into CRITERIO (ID, DESCRIPCION) Values (1, 'PRIMERO')
    Insert Into CRITERIO (ID, DESCRIPCION) Values (2, 'SEGUNDO')
    Insert Into CRITERIO (ID, DESCRIPCION) Values (3, 'TERCERO')
    Insert Into CRITERIO (ID, DESCRIPCION) Values (4, 'CUARTO')
    Insert Into CRITERIO (ID, DESCRIPCION) Values (5, 'QUINTO')

    Insert Into ESTUDIO (ID, DESCRIPCION) Values (1, 'PRIMERO')
    Insert Into ESTUDIO (ID, DESCRIPCION) Values (2, 'SEGUNDO')
    Insert Into ESTUDIO (ID, DESCRIPCION) Values (3, 'TERCERO')
    Insert Into ESTUDIO (ID, DESCRIPCION) Values (4, 'CUARTO')
    Insert Into ESTUDIO (ID, DESCRIPCION) Values (5, 'QUINTO')

    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (1, 1)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (1, 2)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (1, 3)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (1, 4)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (2, 2)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (2, 3)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (2, 4)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (3, 3)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (3, 4)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (4, 4)
    Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (5, 5)

    Si ejecutas la siguiente consulta

    SELECT CRITERIO.DESCRIPCION AS DES_CRITERIO, ESTUDIO.DESCRIPCION AS DES_ESTUDIO
    FROM CRITERIO_ESTUDIO
    INNER JOIN CRITERIO ON CRITERIO.ID=CRITERIO_ESTUDIO.CRITERIO
    INNER JOIN ESTUDIO ON ESTUDIO.ID=CRITERIO_ESTUDIO.ESTUDIO
    WHERE CRITERIO_ESTUDIO.ESTUDIO=4

    DES_CRITERIO    DES_ESTUDIO
    ============    ===========
    PRIMERO         CUARTO
    SEGUNDO         CUARTO
    TERCERO         CUARTO
    CUARTO         CUARTO

    Espero que te sirva

    Un saludo desde Bilbo
    Carlos

    miércoles, 15 de abril de 2015 11:15
  • Hola,

    en mi opinión creo que tu estructura de tablas no es la más óptima.

    Lo que podrías hacer para simplificar todo esto es añadir el campo de idEstudio dentro de tu tabla de Criterios como clave foránea (foreign key).

    De esa manera tu consulta Select para traerte los criterios se va a simplificar y tendrás una relación de 1 a N. (1 Estudio a muchos Criterios). Por otro lado ya no te hará  falta para nada esa tercera tabla de enlace CriteriosEstudio.

    Según la estructura que tienes ahora tendrás que hacer dos JOIN dentro de tu consulta SQL para recoger los datos del DataSet.

    SELECT DescripcionCriterio
    FROM CriteriosEstudio
    INNER JOIN Estudios ON Estudios.Id = CriteriosEstudio.idEstudio
    INNER JOIN Criterios ON Criterios.Id = CriteriosEstudio.idCriterio
    WHERE Estudios.id = 1

    Con mi simplificación te quedaría algo así todo esto:

    Estudios (id, ...)

    Criterios(idCriterio, idEstudio, DescripcionCriterio)

    CriteriosEstudios(te eliminas esta tabla)

    SELECT DescripcionCriterio
    FROM Criterios
    WHERE idEstudio = 1

    Un saludo.




    miércoles, 15 de abril de 2015 11:22
  • Hola Cristian, gracias por tu respuesta.

    La estructura de la tabla Criterios es correcta, ya que se trata de una tabla maestra de Entidades Fuertes por así llamarlas. Si lo hago como dices, tendría la tabla Criterios con el campo DescripcionCriterios duplicados, uno por cada idEstudio ¿Me explico?

    En todo caso podría añadir el campo  DescripcionCriterios en la tabla relación CriteriosEstudios, y ya dispondría del campo que necesito, pero también se duplicaría este dato en esta tabla, y no lo veo fino.

    Gracias nuevamente.

    miércoles, 15 de abril de 2015 12:03
  • Hola J.Carlos, muchas gracias por tu respuesta.

    Creo que no he formulado bien mi pregunta o me he quedado corto en lo que quiero conseguir.

    Todo lo que me has puesto es correcto y así lo hice en su momento.

    El formulario de mantenimiento de estudios es donde se crean los estudios (o se consultan o modifican). En este formulario se crea la Descripción del estudio, y un montón de campos mas que no viene al caso. Ademas de estos campos, al estudio hay que asignarle unos criterios, y pueden ser varios como ya expuse. El grid de los criterios está en ese formulario, pero cuando se está creando un estudio, este grid está vacío. Junto a ese grid puse un boton "+" para añadirle los criterios. Cuando pulsamos +, despliego un formulario pequeñito donde muestro la tabla Criterios y ahí selecciono el/los criterios a asignarle al estudio. Los id de los criterios seleccionados en el formulario pequeñito se los paso a la tabla relación CriteriosEstudio mediante:

    Dim drv as DataRowView = CriteriosEstudioBindingSource.AddNew() 

    drv("idCriterio") = id (este id es recibido del formulario pequeñito de seleccion de Criterios

    drv("idEstudio") = -1 (-1 cuando se está creando un nuevo Estudio, o el valor del id del estudio que se esté editando) 

    ... y en el grid, entonces aparecería el/los criterio seleccionado, pero claro, el grid contiene de enlace el CriteriosEstudioBindingSource, y éste no tiene el campo DescripcionCriterio, por lo que no puede mostrarlo en el grid.

    ¿Qué hice?, En el dataset tipado, en la tabla CriteriosEstudio, además de la consulta principal que te añade el diseñador de DataSet (SELECT idCriterio, idEstudio FROM  CriteriosEstudio) con el método Fill,  yo añadí otra consulta parecida a la que me has puesto tú con el método FillByIdEstudio,  tal como como la siguiente:

    SELECT idEstudio, idCriterio, DescripcionCriterio FROM CriteriosEstudio  AS ce INNER JOIN Criterios AS c ON ce.idCriterio = c.Id AND ce.idEstudio = @iEstudio 


    Para consultar o modificar un estudio existente en la base de datos, en el formulario de mtto de éstos, se cargan en el grid los criterios que se grabaron en su creacion,  haciendo lo siguiente:

    CriteriosEstudiosTableAdapter.FillByIdEstudio(DataSet, n) siendo n el id del Estudio recuperado de la base de datos.

    De esta manera lo hace perfecto, pudiendo añadir mas criterios al estudio y van apareciendo en el grid las descripciones de los criterios. Una vez añadidos todos los criterios, y pulsar "Guardar Estudio", el CriteriosEstudiosTableAdapter.update(dataset.CriteriosEstudios) ejecuta el comando UPDATE generado por el diseñador de dataset sin problema alguno.

    El problema aparece cuando se va a crear un nuevo estudio, el añadir Criterios, no aparecen éstos en el grid, aparec en blanco.

    Llegado a este punto, pensé que existiera otra forma de hacerlo y que la que estaba intentado no era la correcta, pero a medida que te escribo esto, cada vez mas me inclino a pensar que el automatismo de VS con los enlaces de datos con los controles, tiene un límite mas corto del que yo pensaba.

    Creo que esto pasa por hacerlo de forma menos automática y crear más código para ello.

    Voy a coger otro camino, aunque sea mas largo, para resolver esto, creo que tardaré menos.

    Te agradezco tu contestación enormemente, y ya nos vemos por esto lares.

    Gracias y un saludo.



    miércoles, 15 de abril de 2015 16:02
  • Hola:
    El ejemplo que te expongo es a partir de estas premisas que son las que he entendido.
    Quieres añadir 1 registro a la tabla ESTUDIO, y a la vez quieres añadir n registros a la tabla CRITERIO_ESTUDIO (los n registros van en funcion de las filas seleccionadas del DataGridView de CRITERIOS).

    En un Form con 1 DataGridView, 1 Button y 2 TextBox, copia y pega el siguiente codigo

    Option Explicit On
    Option Strict On
    Imports System.Data.SqlClient

    Public Class Form1
        Private msCadenaSQL As String = "Data Source=.\SQLEXPRESS;Initial Catalog=TU_BASE_DE_DATOS;Integrated Security=true"

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            Try
                Dim loDataTable As New DataTable
                Dim lsQuery As String = "Select * From CRITERIO Order By DESCRIPCION"
                Using loConexion As New SqlConnection(msCadenaSQL)
                    Using loDataAdapter As New SqlDataAdapter(lsQuery, loConexion)
                        loDataAdapter.Fill(loDataTable)
                    End Using
                End Using
                'Cargar el DataGridView con los criterios
                Me.DataGridView1.DataSource= loDataTable
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Load", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End Try
        End Sub

        Private Sub btnAñadir_Click(sender As Object, e As EventArgs) Handles btnAñadir.Click
            Try
                Dim lsQuery As String = "Insert Into ESTUDIO (ID, DESCRIPCION) Values (@Id, @Descripcion)"
                Using loConexion As New SqlConnection(msCadenaSQL)
                    loConexion.Open()   ' abrir conexión
                    'Iniciamos una transaccion, hay que añadir una referencia a SysTem.Transactions
                    Using MiTransaccion As New Transactions.TransactionScope
                        'Se añade registro a la tabla ESTUDIO
                        Using loComando As New SqlCommand(lsQuery, loConexion)
                            loComando.Parameters.Add(New SqlParameter("@Id", Me.txtID.Text))
                            loComando.Parameters.Add(New SqlParameter("@Descripcion", Me.txtDescripcion.Text))
                            loComando.ExecuteNonQuery()
                        End Using
                        'Se añaden n registros a la tabla CRITERIO_ESTUDIO
                        For Each loFila As DataGridViewRow In Me.DataGridView1.SelectedRows
                            lsQuery = "Insert Into CRITERIO_ESTUDIO (CRITERIO, ESTUDIO) Values (@Criterio, @Estudio)"
                            Using loComando As New SqlCommand(lsQuery, loConexion)
                                loComando.Parameters.Add(New SqlParameter("@Criterio", loFila.Cells("ID").Value))
                                loComando.Parameters.Add(New SqlParameter("@Estudio", Me.txtID.Text))
                                loComando.ExecuteNonQuery()
                            End Using
                        Next
                        MiTransaccion.Complete()
                    End Using
                End Using
                MessageBox.Show("TRANSACCION FINALIZADA CON EXITO", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Catch Exp As SqlException
                Me.Cursor = Cursors.Default
                MessageBox.Show(Exp.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Catch Exp As Exception
                Me.Cursor = Cursors.Default
                MessageBox.Show(Exp.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End Try
        End Sub
    End Class

    P.D.
    Espero haber entendido bien lo que quieres.

    Te pego una imagen del Form

    Un saludo desde Bilbo
    Carlos


    jueves, 16 de abril de 2015 8:43
  • Hola J.Carlos, ha pasado mucho tiempo desde tu respuesta, y acabo de darme cuenta que no te respondí. Te pido un millón de disculpas; me han ocurrido muchas cosas desde aquellas fechas.

    Respecto a tu respuesta, el problema no era la asignación de los criterios a los estudios, sino mostrar los criterios asignados al estudio en un grid. Cogiendo tu ejemplo, imagina que hay otro grid pero sólo aparecen los criterios que se le ha asignado al estudio. en este caso deberia aparecer un grid con tres estudios: Segundo, Tercero y Cuarto según tu ejemplo.

    De todas formas, ahora que leo la pregunta inicial que hice en este hilo, creo que es estúpida, porque, como ya sabes, cuando se trata de las típicas grillas Maestro-Detalle, el vs te lo hace automatico con su asistente, pero cuando las relaciones entre tablas son un poco mas compleja como en este caso, pues hay que hacerlo a mano. Y eso fue lo que hice. Porque realmente, era una estupidez lo que yo estaba preguntando. 

    Lo dicho, J.Carlos, muchas gracias por tus respuestas, me han servido de mucho porque en tu código he visto maneras muy elegantes que yo debería adoptar.

    Y perdona por la tardanza.

    Saludos.

    miércoles, 7 de octubre de 2015 8:00