Harlequin: [C#/WinForms/SQL] DataViewGrid und ForeignKeys

Yerf!

ich sitz hier mal wieder vor dem C#-WindowsForms Projekt und frag mich, wie ich am besten mit ForeignKeys im DataViewGrid umgehe...

Ausgangslage: ich habe Tabellen mit Daten bei denen manche Spalten IDs sind die sich auf andere Tabellen beziehen (normale 1:n Beziehungen). Das DataViewGrid fülle ich direkt aus der Tabelle (momentan mittels select * from tabelle, wird noch auf die expliziten Spalten geändert) und so sehe ich in diesen Spalten nur eine Zahl (die ID) anstelle eines "schönen" Strings.

In der Bearbeitungsmaske hole ich mir noch eine Zuordnungsliste um eine Dropdown-Box mit allen Möglichkeiten zu befüllen, so dass der User dort aussagekräftige Namen hat, im Hintergrund wird aber die ID in die dem DVG zugundeliegnde tabelle eingefügt.

Ziel: ich hätte jetzt gern im DVG ebenfalls die schönen Bezeichner anstelle der IDs, aber ohne das es mir meine vorhandene Logik zum Laden und Speichern der Datensätze zerhaut...

Momentane Lösung: ich greif ins Rendering des DVG ein und ändere den FormatString der Zelle auf auf den Namen aus der Zuordnungsliste... kommt mir aber wie ein übler Hack vor und das Sortieren im DVG funktioniert damit auch nicht richtig (weil weiterhin auf Basis der IDs sortiert wird)

Ideen:

  • Ich hol mir aus der Datenbank die Namen anstelle der IDs und Joine beim Speichern über alle beteiligten Tabellen um wieder die IDs einfügen zu können (Performance, Aufwand?)
  • Ich hol mir Namen und IDs aus der Datenbank und blende die ID-Spalten aus. Beim ändern eines Datensatzes muss ich beide Spalten synchron halten da ich Namen anzeige und ID speichere (gangbarer Weg oder auch Murks?)
  • Ich bekomm es irgendwie hin dem DVG die Beziehungen zu erklären... (geht das irgendwie?)
  • weils mir grad beim tippen noch so einfällt: kann man in C# ENUMS dynamisch erstellen und wäre das ein möglicher Weg?

Oder gibt es einen anderen Weg? Hat damit schon mal jemand hantiert und einen Lösungsweg parat?

Gruß,

Harlequin

--
RIP --- XHTML 2
nur die Besten sterben jung
  1. Hi!

    Ziel: ich hätte jetzt gern im DVG ebenfalls die schönen Bezeichner anstelle der IDs, aber ohne das es mir meine vorhandene Logik zum Laden und Speichern der Datensätze zerhaut...

    • Ich hol mir aus der Datenbank die Namen anstelle der IDs und Joine beim Speichern über alle beteiligten Tabellen um wieder die IDs einfügen zu können (Performance, Aufwand?)

    Das Feld mit Join oder in deinem Fall besser mit korrelierter Subquery hinzuzuholen, ist eine Methode, wenn du nur anzeigen willst.

    • Ich hol mir Namen und IDs aus der Datenbank und blende die ID-Spalten aus. Beim ändern eines Datensatzes muss ich beide Spalten synchron halten da ich Namen anzeige und ID speichere (gangbarer Weg oder auch Murks?)

    Nicht nötig.

    • Ich bekomm es irgendwie hin dem DVG die Beziehungen zu erklären... (geht das irgendwie?)

    Was hältst du vom Spaltentyp DataGridViewComboBoxColumn?

    • weils mir grad beim tippen noch so einfällt: kann man in C# ENUMS dynamisch erstellen und wäre das ein möglicher Weg?

    Vielleicht mit Reflection. Ist aber sicher zu aufwendig oder hat andere Nachteile.

    Lo!

    1. Yerf!

      • Ich hol mir aus der Datenbank die Namen anstelle der IDs und Joine beim Speichern über alle beteiligten Tabellen um wieder die IDs einfügen zu können (Performance, Aufwand?)

      Das Feld mit Join oder in deinem Fall besser mit korrelierter Subquery hinzuzuholen, ist eine Methode, wenn du nur anzeigen willst.

      Das Problem ist, das die DataTable schlussendlich nicht nur zum Anzeigen verwendet wird, sondern die Rows in ihr auch bearbeitet und wieder in die Datenbank zurückgeschrieben werden (allerdings nicht über einen angebundenen Adapter sondern über eigene Methoden die die Events der DataTable abfangen)

      • Ich hol mir Namen und IDs aus der Datenbank und blende die ID-Spalten aus. Beim ändern eines Datensatzes muss ich beide Spalten synchron halten da ich Namen anzeige und ID speichere (gangbarer Weg oder auch Murks?)

      Nicht nötig.

      Aber wie speichere ich dann nach einer Änderung ab? Beim Speichern Joins/Subquerys verwenden wie in Vorschlag 1? Oder wie stell ich die Beziehung zwischen Name und ID her, die Lookuptabelle für die Comboboxen nehmen? (wobei ich dann zum Value den Key suchen müsste im Dictionary...)

      • Ich bekomm es irgendwie hin dem DVG die Beziehungen zu erklären... (geht das irgendwie?)

      Was hältst du vom Spaltentyp DataGridViewComboBoxColumn?

      Aber wie versorg ich den mit Daten? Ich hab da nichts vernünftiges im Netz gefunden (außer Enums, aber die kann ich nicht fest definieren, siehe letzter Punkt). Wobei ich in der Liste keine Combobox brauch, das DataGridView ist nur für die Anzeige (editieren über eigene Maske für einen Datensatz), aber die DataTable dahinter muss ich bearbeiten, da darüber das Speichern der Änderungen läuft (außer ich schmeiß das ganze Konzept nochmal um... würd ich aber ungern machen, weils ansonsten gut läuft)

      • weils mir grad beim tippen noch so einfällt: kann man in C# ENUMS dynamisch erstellen und wäre das ein möglicher Weg?

      Vielleicht mit Reflection. Ist aber sicher zu aufwendig oder hat andere Nachteile.

      War nur so eine Idee ob ich auf den Weg beide Informationen (ID und Text) in einer Column speichern kann. Die Enums fest im Code hinterlegen geht nicht, weil sich der Inhalt der Tabelle ändern kann.

      Gruß,

      Harlequin

      --
      RIP --- XHTML 2
      nur die Besten sterben jung
      1. Hi, hol beide Tabellen aus der DB einzeln in (zum Bleistift) ein DataSet. Binde das Grid an die Tabelle die du darstellen willst. Binde die Kombobox an die 2. Tabelle und ei SelectedItem Eigenschaft der Kombobox an den Spaltenwert aus der ersten Tabelle.

        Gruss aus Vegas,
        Frank

        1. Yerf!

          Hi, hol beide Tabellen aus der DB einzeln in (zum Bleistift) ein DataSet. Binde das Grid an die Tabelle die du darstellen willst. Binde die Kombobox an die 2. Tabelle und ei SelectedItem Eigenschaft der Kombobox an den Spaltenwert aus der ersten Tabelle.

          Sowas in der Art hab ich mit der Combobox-Spalte des DVG versucht aber nicht hinbekommen... gibts dafür irgendwo gute Beispiele? Das wäre die elegante Lösung.

          Gruß,

          Harlequin

          --
          RIP --- XHTML 2
          nur die Besten sterben jung
          1. Hi!

            Sowas in der Art hab ich mit der Combobox-Spalte des DVG versucht aber nicht hinbekommen... gibts dafür irgendwo gute Beispiele? Das wäre die elegante Lösung.

            Das .NET hat eigentlich eine sehr gute Dokumentation. Nahezu jede Eigenschaft ist mit einem Beispiel erklärt. Den Cursor im Visual Studio auf ein Element stellen, F1 drücken und kommst zur entsprechenden Hilfeseite (besser online als eine alten Offline-Snapshot, kannst du dir ja in den Optionen einstellen). Neben den Elementbeschreibungen findest du dort auch Walkthroughs, HowTos und Samples (gibts bestimmt auch deutsche Bezeichnungen, aber ich lese Doku vorwiegend auf Englisch). Diese stehen manchmal unten unter See also verlinkt, manchmal findet man sie auch, wenn man den Menübaum auf der linken Seite passend abklappert (am besten in der Classic-Ansicht).

            Lo!

            1. Yerf!

              Ok, ich habs inzwischen in der MSDN gefunden, das mit der ComboBox-Spalte klappt jetzt einwandfrei. Damit löst sich das Problem eigentlich von selbst (außer es stört sich noch jemand an den Combobox-Icons neben dem Bezeichner... aber dann bau ich einfach die zusätzlichen Spalten rein)

              Gruß,

              Harlequin

              --
              RIP --- XHTML 2
              nur die Besten sterben jung
      2. Hi!

        Was hältst du vom Spaltentyp DataGridViewComboBoxColumn?
        Aber wie versorg ich den mit Daten? Ich hab da nichts vernünftiges im Netz gefunden (außer Enums, aber die kann ich nicht fest definieren, siehe letzter Punkt). Wobei ich in der Liste keine Combobox brauch, das DataGridView ist nur für die Anzeige (editieren über eigene Maske für einen Datensatz), aber die DataTable dahinter muss ich bearbeiten, da darüber das Speichern der Änderungen läuft (außer ich schmeiß das ganze Konzept nochmal um... würd ich aber ungern machen, weils ansonsten gut läuft)

        Also geht es dir für das DGV doch nur um die Anzeige. Dann erweitere das SELECT um den Klartext (Subquery oder Join), und die DataTable um das eine Feld. Für das Bearbeiten in der separaten Maske nimmst du ein Combo-Feld mit Lookup, das sind die Eigenschaften DataSource, ValueMember und DisplayMember. Das hinzugefügte Feld lässt du dabei außer Betracht. Auch Insert- und Update-Statement müssen das Anzeigefeld ignorieren, die schreiben nur den Wert aus dem eigentlichen Fremdschlüsselfeld, der ja duch das Combofeld richtig gesetzt wurde. Bei Insert und Update musst du außerdem dafür sorgen, dass danach die Daten des Datensatzes erneut gelesen werden, was über eine Option im TableAdapter einstellbar ist.

        Lo!

        1. Yerf!

          Jepp, das DVG ist nur für die Anzeige. Was mich halt etwas irritiert hat war dein "unnötig" in deiner ersten Antwort... wenn ich das Namensfeld *zusätzlich* mit aufnehme sollte ich die ID im DVG ausblenden, da ich ansonsten eine überflüssige Spalte hab (und wenn ich die ID im select weglasse fehlt sie mir in der Tabelle um sie speichern zu können)

          Das Speichern erledigt nicht die Eingabemaske direkt sondern der DataView der um die DataTable gestülpt ist, deswegen muss ich alle Informationen die ich speichern will auch in die DataTable schreiben. (da war doch zuletzt diese Event-Sache... das ist genau dieser DataView)

          Aber ich denke dass das wohl der beste Weg ist. Die ID Spalten ausblenden ist jetzt nicht wirklich dramatisch und ich hab alles an Funktionalität das ich brauche (das aktualisieren von DVG bekomm ich sicher auch hin)

          (Die Eingabemaske mit der Dropdown-Box funktioniert jetzt schon)

          Danke fürs mit durchdenken.

          Gruß,

          Harlequin

          --
          RIP --- XHTML 2
          nur die Besten sterben jung
          1. Hi!

            Jepp, das DVG ist nur für die Anzeige. Was mich halt etwas irritiert hat war dein "unnötig" in deiner ersten Antwort... wenn ich das Namensfeld *zusätzlich* mit aufnehme sollte ich die ID im DVG ausblenden, da ich ansonsten eine überflüssige Spalte hab (und wenn ich die ID im select weglasse fehlt sie mir in der Tabelle um sie speichern zu können)

            Bei dem "unnötig" kannte ich deine Konstellation noch nicht so genau. Ich nahm an, dass das DGV auch zu Editieren herhalten soll und dann reichte da eine ComboBox-Spalte. Mit den neuen Erkenntnissen, dass das DGV nur zum Anzeigen und das Ändern anderswo geschieht, muss ich das sogar empfehlen.

            Also nochmal im Ganzen: Die DataTable bekommt zusätzlich das Klartextfeld und das Select fragt es geeignet ab (Subquery, Join). Ignorieren beim Anzeigen - klar, du nimmst natürlich nur die Felder aus der DT in das DGV auf, die du anzeigen willst. Für das Editieren bekommt nur das FK-Feld ein Element, nämlich eine normale ComboBox. Dort befüllst du bereits genannten Eigenschaften, für die Ausklappwerte.

            Diese Lösung bietet keine Aktualisierung des Klartextfeldes in der DT, wenn du in der ComboBox was neues auswählst. Ein einfacher Hack wäre, beim Speichern in die DT (nicht beim Change-Event der ComboBox, denn danach kann immer noch ein Abort des gesamten Editierens erfolgen) den ausgewählten Klartext in die DT zu übertragen, ansonsten bekommst du da eine Aktualisierung erst beim erneuten Lesen aus der Quelle nach dem Update aller Änderungen im DataSet (oder zumindest der einen Tabelle daraus).

            Alternativ kannst du auch im DGV eine CB-Column nehmen und auf ReadOnly setzen, dann müsste diese sich automatisch bei Änderungen in der DT die Werte umschreiben. Wobei ich mir jetzt nicht sicher bin, ob sich bereits auf dem Schirm befindliche Werte aktualisieren, wenn sich hintenrum was ändert. Auf alle Fälle solltest du den neuen Wert beim Befüllen des DGV sehen. Aber auch beim ReadOnly zeigt die CB das Auswahldreieck an der rechten Seite an. Wenn dich das stört, dann geht das so natürlich nicht.

            Lo!

            1. Yerf!

              Bei dem "unnötig" kannte ich deine Konstellation noch nicht so genau. Ich nahm an, dass das DGV auch zu Editieren herhalten soll und dann reichte da eine ComboBox-Spalte. Mit den neuen Erkenntnissen, dass das DGV nur zum Anzeigen und das Ändern anderswo geschieht, muss ich das sogar empfehlen.

              Ah, ok. Das DGV dient nur zur Übersicht, vermutlich werden in manchen Fällen dort auch weitere Spalten ausgeblendet, so dass man darüber sowieso nicht den kompletten Datensatz editieren könnte.

              Diese Lösung bietet keine Aktualisierung des Klartextfeldes in der DT, wenn du in der ComboBox was neues auswählst. Ein einfacher Hack wäre, beim Speichern in die DT (nicht beim Change-Event der ComboBox, denn danach kann immer noch ein Abort des gesamten Editierens erfolgen) den ausgewählten Klartext in die DT zu übertragen

              Jepp, sowas in der Art war mir klar (das "synchronisieren" aus dem ersten Posting) und werd ich wohl auch machen. Das ganze sollte aber auch im Change-Event funktionieren, da ich beim Abbruch ein Cancel auf die Data-Table mache und die dann alle Änderungen verwirft. Ich werds sehen.

              Alternativ kannst du auch im DGV eine CB-Column nehmen und auf ReadOnly setzen, dann müsste diese sich automatisch bei Änderungen in der DT die Werte umschreiben.

              Das mit der CB-Spalte muss ich mir nochmal anschauen. Ich hatte bisher auch in der Hilfe keine passenden Beispiele gefunden. (Ich hätt gern WPF, da ist das irgendwie alles einfacher...)

              Gruß,

              Harlequin

              --
              RIP --- XHTML 2
              nur die Besten sterben jung
              1. Hi!

                Das mit der CB-Spalte muss ich mir nochmal anschauen. Ich hatte bisher auch in der Hilfe keine passenden Beispiele gefunden. (Ich hätt gern WPF, da ist das irgendwie alles einfacher...)

                Schau mal auf die Seite DataGridViewComboBoxColumn Class. Unter der Auflistung der Mitglieder ist ein Codebeispiel, was ziemlich lang ist. Die interessante Stelle ist aber die Methode SetAlternateChoicesUsingDataSource. Die setzt die DataSource letzlich auf eine DT mit nur einem Feld. In deinem Fall musst du aus der Klartext-Tabelle zwei Felder nehmen, den Primärschlüssel und den Text. Das Beispiel setzt nun beide, ValueMember und DisplayMember, auf den Feldnamen der DT. Du setzt hingegen VM auf den PK-Feldnamen und DM auf den Text-Feldnamen. Das war's schon.

                Lo!

                1. Yerf!

                  Schau mal auf die Seite DataGridViewComboBoxColumn Class. Unter der Auflistung der Mitglieder ist ein Codebeispiel, was ziemlich lang ist.

                  Grad eben im anderen Zweig geantwortet ;-)

                  Aber ja, mit dem Beispiel hats dann geklappt. Keine Ahnung wie ich es anfangs geschafft hab das zu übersehen... vermutlich nicht direkt unter dem Typ gesucht.

                  Gruß,

                  Harlequin

                  --
                  RIP --- XHTML 2
                  nur die Besten sterben jung