Un ListBox y una relación n:m

Supongamos que tenemos una relación n:m facilita. Por ejemplo, series y los géneros de estas series. Digamos que tengo mi tabla de series con su clave primaria IdSeries, mi tabla de géneros con su clave IdGenero y la otra que tiene únicamente los campos IdSerie e IdGenero para hacer la relación. Digamos también que quiero mostrar los géneros de cada serie en un ListBox, que llamaremos lstGeneros. Y digamos, de paso, que quiero usar ese ListBox no sólo para mostrar los géneros de la serie, sino también para seleccionarlos en altas y modificaciones. Uhm, ya la cosa se complica.

Vayamos por partes: visualización. Esto es lo más fácil y hay opciones para todos los gustos. Por ejemplo, podría generar una vista en la base de datos que me englobase las tablas de género y «géneros de series» y montar un dataset tipado con la tabla de series, la vista y la relación entre ambas. De ahí a montar un maestro-detalle de tutorial, sólo que con un listbox en lugar de un datagridview, sólo hay un paso.

Podría tener un dataset tipado con las tres tablas completas y cargadas en memoria y usar una consulta LINQ para sacar un listado de los IdGenero y géneros y ligarla al listbox cada vez que cambie de serie. Podría hacer la consulta a la base de datos en cada cambio de series. Podría, ¡qué sé yo!, usar LINQ to SQL.

Para las altas también es fácil: muestro en el listbox toda la tabla de géneros y permito la selección múltiple. Por supuesto, como ValueMember tengo el IdGenero. Al aceptar la nueva alta sólo tengo que recorrer el listbox, coger los IdGenero de los géneros seleccionados, coger el IdSerie de la nueva serie y crear las nuevas filas de la tabla «géneros de series» con estos valores. Luego, a guardar todo.

El problema viene con las modificaciones. Para empezar, tengo que marcar los géneros ya existentes para esa serie. Ahora el problema es que el usuario puede tanto marcar géneros nuevos como desmarcar algunos previamente existentes. Uff. En fin, como ejemplo, supongamos que trabajo con un dataset tipado con las tres tablas, Series, GeneroSerie y Generos. Primero necesitamos coger los IdGenero de los elementos marcados en el lstGeneros. También necesitamos los géneros de la serie previamente existentes. Digamos que los obtengo así:

Dim Generos As New List(Of Integer)
For i As Integer = 0 To lstGeneros.Items.Count - 1
    If Me.lstGeneros.GetSelected(i) Then
        Generos.Add(CInt(TryCast(Me.lstGeneros.Items(i),  _
        DataRowView).Item(0)))
    End If
Next
Dim GenerosPrevios = From e In Me.dsSeries.GeneroSerie _
                     Where e.IdSerie = Me._SerieActual

Con esto ya podemos trabajar. Primero, buscamos los géneros nuevos y los añadimos a la tabla GeneroSerie.

Dim Encontrado As Boolean = False
Dim GenerosATrabajar As New List(Of Integer)
For Each Genero In Generos 'Géneros marcados en el ListBox
    For Each Fila In GenerosPrevios
        Encontrado = (Fila.IdGenero = Genero)
        If Encontrado Then Exit For
    Next
    If Not Encontrado Then 'añadimos fila
        GenerosATrabajar.Add(Genero)
    End If
Next
Dim rwNuevoGeneroSerie As SeriesDataSet.GeneroSerieRow
For Each Genero In GenerosATrabajar
    rwNuevoGeneroSerie = _dsSeries.GeneroSerie. _
                         NewGeneroSerieRow
    rwNuevoGeneroSerie.IdGenero = Genero
    rwNuevoGeneroSerie.IdSerie = Me._SerieActual
    _dsSeries.GeneroSerie.AddGeneroSerieRow( _
                         rwNuevoGeneroSerie)
Next

Y luego hacemos lo contrario, buscamos los que se han desmarcado, que tendremos que borrar:

GenerosATrabajar.Clear()
For Each Fila In GenerosPrevios
    For Each Genero In Generos
        Encontrado = (Fila.IdGenero = Genero)
        If Encontrado Then Exit For
    Next
    If Not Encontrado Then
        'Nos quedamos con el idGenero para borrarlo
        GenerosATrabajar.Add(Fila.IdGenero)
        'Hay que borrar la fila, pero así no podemos
        'porque afectamos a las filas de GenerosPrevios
        'y se joroba el foreach,
        'así que apuntamos los generos y lo hacemos luego 
    End If
Next
For Each Genero In GenerosATrabajar
    _dsSeries.GeneroSerie.FindByIdGeneroIdSerie(Genero, _
                                 Me._SerieActual).Delete()
Next

Nos quedaría guardarlo todo en la base de datos y listo. La utilidad de esto es relativa: en el momento en que tengamos que mostrar más de un campo, el listbox no nos vale. De igual modo, si la tabla Géneros tiene demasiados registros, va a ser confuso mostrarlos todos en un listbox y quizás sea más práctico un formulario de búsqueda o cualquier otra forma que se nos ocurra. Pero para mí, en este caso, y en otros pocos más en donde lo he empleado, me parece una buena solución.

Un comentario en «Un ListBox y una relación n:m»

  1. Pingback: Quemando Cromo » Blog Archive » Jugando con DataTables

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.