Datenbank in TreeView abbilden

  • VB.NET

Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von CamFreak.

    Datenbank in TreeView abbilden

    Hallo Vb-Community
    ich bräuchte mal wieder eure Hilfe... ?(
    Und zwar habe ich eine Access Datenbank (Welche ihr im Anhang findet),
    die ich im visual Studio Projekt (auch im Anhang) eingebuden habe. In der DB sind mehrere Tabellen welche über
    Beziehungen miteinnander verknüpft sind. Diese Möchte ich in einem TreeView abbilden, sodass der TreeView die DB wie im Anhang abgebildet(TreeView.png) ist, abbildet.
    Die Grafik links(DB-Beziehungen_Grafik.png) veranschaulicht die Datenabnk, welche man sich aber auch runterladen kann
    Ich habe mir auch den Beitrag von ErfinderDesRades ( die vier Views auf Video ),
    die dazugehörigen Videos und viele weitere Beiträge angeschaut und stehe leider immernoch auf dem Schlauch :/ :/
    Ich hoffe ihr könnt mir helfen
    aufjedenfall vielen vielen dank schon mal im Vorraus :rolleyes:
    PS: ich bin auf dem Gebiet noch ein newby
    Bilder
    • DB-Beziehungen_Grafik.PNG

      10,65 kB, 692×297, 441 mal angesehen
    • TreeView.PNG

      12,63 kB, 424×523, 407 mal angesehen
    Dateien

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „CamFreak“ ()

    OK, danke für diesen Hinweis, allerdings wäre es sehr schön, wenn man es mit dem TreeView realisieren könnte. Ich muss ja z.B. kein DataBinding haben(die Datenbank ändert sich nämlich nicht. Ich muss im Prinzip nur eine Ordnerstruktur im TreeView anzeigen), sondern es wäre schön, wenn die Nodes durch eine While Schleife, welche am Start des Programms die Datenabnk durchgeht, erzeugt werden

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „CamFreak“ ()

    paar Punkte dazu:
    1. Dafür brauchst du keine Datenbank.
      So 20000 Datensätze kann man locker in ein typisiertes Dataset halten, was man mit Dataset.WriteXml auf Platte schreibt.
      Du willst ja eh die ganze Datenbank in den Speicher laden - wie gesagt: eine Datenbank hat in solchem Fall keinen Vorteil gegenüber einer einfachen Xml-Datei, wohl aber viele Nachteile
    2. Ein Treeview ist für solche Datenmenken keine userfreundliche Präsentation.
      Es gibt Staaten mit hunderten von Städten - wenn du so einen Treenode dann erweiterst, verlierst du zwangsläufig die Übersicht, in welchem Staat/Kontinent du grade herumbaldowerst.
    3. Den Treeview bauste nicht mit einer WhileSchleife auf, sondern mit einer 3-fach geschachtelten ForEach - weil dein Datenmodell 3 Ebenen darstellt.
    Ist bestimmt nicht der eleganteste Code, aber zeigt wie.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.IO
    4. Imports System.Data.OleDb

    VB.NET-Quellcode

    1. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    2. Dim cs As String
    3. Dim mydbpath As String = "Datenbank.accdb"
    4. cs = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Jet OLEDB:Database Password=", mydbpath)
    5. Me.StartConnection(cs, mydbpath, 2)
    6. End Sub
    7. Private Function StartConnection(ByVal cs As String, ByVal MyMdbPathName As String, ByVal intSelection As Integer) As DatenbankDataSet
    8. StartConnection = Nothing
    9. If (intSelection < 0) Or (intSelection > 2) Then Exit Function
    10. Dim conn As New OleDb.OleDbConnection(cs)
    11. Dim ds As New DatenbankDataSet
    12. Dim aa1 As Integer = CInt(ds.Tables.Count - 1)
    13. Dim myTable As String
    14. Try
    15. If File.Exists(MyMdbPathName) Then
    16. conn.Open()
    17. For ii As Integer = 0 To aa1
    18. myTable = ds.Tables(ii).TableName
    19. LoadData(ds, conn, myTable)
    20. Next
    21. conn.Close()
    22. Call TreeViewErstellen(ds, MyMdbPathName)
    23. End If
    24. Catch ex As Exception
    25. MsgBox(ex.Message)
    26. End Try
    27. End Function
    28. Private Sub LoadData(ByRef ds As DatenbankDataSet, ByVal conn As OleDb.OleDbConnection, ByVal myTable As String)
    29. Dim cmd As New OleDbCommand()
    30. Dim da As New OleDbDataAdapter
    31. Try
    32. With cmd
    33. .Connection = conn
    34. .CommandText = "SELECT * FROM " & myTable
    35. End With
    36. With da
    37. .SelectCommand = cmd
    38. .TableMappings.Add("Table", myTable)
    39. .Fill(ds)
    40. End With
    41. ds.AcceptChanges()
    42. Catch ex As Exception
    43. MsgBox(ex.Message)
    44. End Try
    45. End Sub
    46. Private Sub TreeViewErstellen(ByRef ds As DatenbankDataSet, ByVal MyMdbPathName As String)
    47. Dim dt1 As DataTable, aa1, aa2 As Integer
    48. Try
    49. If File.Exists(MyMdbPathName) Then
    50. Me.TreeView1.Nodes.Clear()
    51. Me.TreeView1.Nodes.Add(New TreeNode(MyMdbPathName))
    52. aa1 = ds.Tables.Count - 1
    53. For i As Integer = 0 To aa1
    54. Me.TreeView1.Nodes(0).Nodes.Add(New TreeNode(ds.Tables(i).TableName))
    55. Me.TreeView1.Nodes(0).Nodes(i).Tag = ds.Tables(i)
    56. dt1 = ds.Tables(i) : aa2 = dt1.Columns.Count - 1
    57. For y As Integer = 0 To aa2
    58. Me.TreeView1.Nodes(0).Nodes(i).Nodes.Add(dt1.Columns(y).ColumnName)
    59. Me.TreeView1.Nodes(0).Nodes(i).Nodes(y).Tag = dt1.Columns(y)
    60. Next
    61. Next
    62. Me.TreeView1.Tag = Nothing
    63. Me.TreeView1.ExpandAll()
    64. End If
    65. Catch ex As Exception
    66. MsgBox(ex.Message)
    67. End Try
    68. End Sub


    Freundliche Grüsse

    exc-jdbi
    OK, du hast mir wirklich mega weitergeholfen. Danke Danke Danke. ^^
    Ich habe jetzt nur noch abgeändert, dass nicht die Spaltenüberschreiften der Tabellen, sondern der Tabelleninhalt im TreeView angezeigt wird, so wie es oben in TreeView.png zu sehen ist.
    Ich habe dazu nur im Sub TreeViewErstellen den Code wie folgt abgeändert
    Allerding stoße ich hier irgendwie auf ein Problem, und zwar, dass ich
    1. nicht weis wofür TreeView.Nodes.Tag sein soll (durch google werde ich da irgendwie auch nicht schlauer) und
    2. dass er mir immer den Fehler "Das angegebene Argument liegt außerhalb des gültigen Wertebereichs. Parametername: Index" anzeigt
    ich habe dazu nur im Sub TreeViewErstellen den Code wie folgt abgeändert. Ich wäre mega dankbar, wenn mir irgendjemand den Entscheidenen Tipp geben würde
    Kurzum: Ich muss in dem TreeView den Inhalt der Tabellen wiederspiegeln. Der Code von @exc-jdbi ist gut, spiegelt aber nur die Spaltenüberschriften im TreeView wieder.

    VB.NET-Quellcode

    1. Private Sub TreeViewErstellen(ByRef ds As DatenbankDataSet, ByVal MyMdbPathName As String)
    2. Dim dt1 As DataTable, aa1, aa2, ID1, ID2 As Integer
    3. Try
    4. If File.Exists(MyMdbPathName) Then
    5. Me.TreeView1.Nodes.Clear()
    6. Me.TreeView1.Nodes.Add(New TreeNode(MyMdbPathName))
    7. aa1 = ds.Kontinent.Rows.Count - 1
    8. For i As Integer = 0 To aa1
    9. Me.TreeView1.Nodes(0).Nodes.Add(New TreeNode(ds.Kontinent.Rows(i)(1)))
    10. 'Me.TreeView1.Nodes(0).Nodes(i).Tag = ds.Tables(i)
    11. dt1 = ds.Tables(i)
    12. aa2 = ds.Land.Rows.Count - 1
    13. ID1 = ds.Kontinent.Rows(i)(0)
    14. For y As Integer = 0 To aa2
    15. If ds.Land.Rows(y)(2) = ID1 Then
    16. Me.TreeView1.Nodes(0).Nodes(i).Nodes.Add(ds.Land.Rows(y)(1))
    17. 'Me.TreeView1.Nodes(0).Nodes(i).Nodes(y).Tag = dt1.Columns(y)
    18. ID2 = ds.Land.Rows(y)(0)
    19. For z As Integer = 0 To ds.Stadt.Rows.Count - 1
    20. If ds.Stadt.Rows(z)(1) = ID2 Then
    21. Me.TreeView1.Nodes(0).Nodes(i).Nodes(y).Nodes.Add(ds.Stadt.Rows(z)(0))
    22. 'Me.TreeView1.Nodes(i).Nodes(y).Nodes(z).Tag = ds.Tables(z)
    23. End If
    24. Next
    25. End If
    26. Next
    27. Next
    28. Me.TreeView1.Tag = Nothing
    29. Me.TreeView1.ExpandAll()
    30. End If
    31. Catch ex As Exception
    32. MsgBox(ex.Message)
    33. End Try
    34. End Sub
    Tag ist eine Control-Property, die Du mit einem beliebigen Objekt füllen kannst, um damit quasi irgendwas zu machen.
    In welcher Zeile kommt denn der Fehlercode? Zeile#11 sieht verdächtig aus. Hast Du im DataSet soviele Tabellen wie Zeilen in Tabelle 1?
    Weiter hab ich nicht geschaut, da mit MsgBox der VisualBasic6-Namespace noch aktiv ist. Und die ganzen Variable mit lustigen Namen wie aa1, aa2 sind weder vielsagend noch notwendig. Aber das ist ein anderes Thema.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Den 1. Kontinent macht er noch problemlos, nur wenn es an den 2. (Asien) ran geht. Dann schreibt er noch CHina als Land und bei der 1. Stadt, welche er in Zeile 21 schreiben soll, bringt er den Fehler
    Hast Du im DataSet soviele Tabellen wie Zeilen in Tabelle 1?
    nein, wo sol denn das stehen??? vllt ist das ja der Fehler ?(
    Wie gesagt, Code-Zeile#11: dt1 = ds.Tables(i)

    VB.NET-Quellcode

    1. aa1 = ds.Kontinent.Rows.Count - 1
    2. For i As Integer = 0 To aa1
    3. '[...]
    4. dt1 = ds.Tables(i)

    Die ite Tabelle wird hergenommen. i geht von 0 bis aa1. Und aa1 ist ds.Kontinent.Rows.Count - 1, also die Anzahl der Zeilen - 1. Kommt mir komisch vor.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Wenn du das GridView auswählst und den kleinen "Pfeil" oben rechts drückst erscheint ein Drobdownmenu;
    "Spalten bearbeiten" auswählen und dort kannst du dann mit der "Visible" Eigenschaft bestimmen, Ob die TableRow im GridView angezeigt werden soll, oder nicht.

    edit: Habe da wohl was missverstanden, aber vieleicht ist die Info ja trotzdem hilfreich.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „FormFollowsFunction“ ()

    Es gibt kein DGV. Nur ein TreeView. Der Wunsch des TEs. auch wenn es alles etwas ... komplizierter macht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Also ich habe gerade mal die Zeile

    VB.NET-Quellcode

    1. dt1 = ds.Tables(i)
    auskommentiert und es ändert sich nichts am Ergebnis. ?(
    Er springt immernoch am selben Punkt raus und der selbe Fehler ist immernoch da
    Bilder
    • Ergebniss mit Fehlermeldung.PNG

      14,1 kB, 816×481, 405 mal angesehen

    VaporiZed schrieb:

    Es gibt kein DGV. Nur ein TreeView.

    Ich sollte wohl besser mal inne Heia gehen. :D

    Jute Nacht :sleeping:
    Schmeiß mal das Try-Catch und die MessageBox raus. Durch solche Konstrukte grätschst Du Dir selber zwischen die Beine. Sobald Du es weglässt, wird nämlich in der betreffenden Codezeile angezeigt, wo was nicht passt und Du kannst viel schneller das Problem finden und lösen. Also beim Code aus Post#6 Zeile#3 und #31-#31 auskommentieren und nochmal versuchen. Der Fehler bleibt! Aber er wird an der Verursacherstelle angezeigt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hab ich gemacht. es ist alles beim alten geblieben. Die msgBox wird aus dem StartConnection Sub ausgegeben.
    Ich habe jz oben den Try-Block (im StartConnection Sub) auch weggemacht und jz bekommt ich diese Fehlermeldung
    Bilder
    • Ergebniss mit Fehlermeldung2.PNG

      61,35 kB, 1.233×533, 286 mal angesehen
    Wir kommen der Sache näher.
    Da tipp ich doch einfach mal darauf, dass y falsch ist. y ist eine Schleifenvariable, die immer um 1 erhöht wird. Aber nicht bei jedem Schleifendurchgang wird ein neuer ChildNode erstellt. Daher wird die Indizierung .Nodes(y). schon sehr bald scheitern. Da müsstest Du ne eigene Node-Zählvariable mitdefinieren, die immer nur dann erhöht wird, wenn wirklich ein neuer Node dazukommt. Oder gleich mit NodeCount() - 1 (oder war es Nodes.Count() - 1?) arbeiten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Also, der Fehler kommt jz nicht mehr :thumbsup: , und ich arbeite mit nodes.count und einer Variable. Es werden jz nur nicht die Städte richtig zugeodnet

    EDIT: Habs Jetzt :saint: 8-) :thumbsup:
    Nodes.Count war der hilfreiche Tipp. Danke Danke Danke <3 :D :thumbup:

    Hier nochmal den ganzen Code, für alle die das gleiche Problem haben. Ich habe alles von oben aus Beitrag #5 von @exc-jdbi (auch an dich vielen Hezlichen Dank :thumbsup: :thumbup: <3 ), nur den Sub TreeViewErstellen hab ich wie Folgt

    VB.NET-Quellcode

    1. Private Sub TreeViewErstellen(ByRef ds As DatenbankDataSet, ByVal MyMdbPathName As String)
    2. Dim dt1 As DataTable, aa1, aa2, ID1, ID2, y1 As Integer
    3. If File.Exists(MyMdbPathName) Then
    4. Me.TreeView1.Nodes.Clear()
    5. Me.TreeView1.Nodes.Add(New TreeNode(MyMdbPathName))
    6. aa1 = ds.Kontinent.Rows.Count - 1
    7. For i As Integer = 0 To aa1
    8. Me.TreeView1.Nodes(0).Nodes.Add(New TreeNode(ds.Kontinent.Rows(i)(1)))
    9. 'Me.TreeView1.Nodes(0).Nodes(i).Tag = ds.Tables(i)
    10. 'dt1 = ds.Tables(i)
    11. aa2 = ds.Land.Rows.Count - 1
    12. ID1 = ds.Kontinent.Rows(i)(0)
    13. For y As Integer = 0 To aa2
    14. If ds.Land.Rows(y)(2) = ID1 Then
    15. Me.TreeView1.Nodes(0).Nodes(i).Nodes.Add(ds.Land.Rows(y)(1))
    16. 'Me.TreeView1.Nodes(0).Nodes(i).Nodes(y).Tag = dt1.Columns(y)
    17. ID2 = ds.Land.Rows(y)(0)
    18. For z As Integer = 0 To ds.Stadt.Rows.Count - 1
    19. If ds.Stadt.Rows(z)(1) = ID2 Then
    20. Me.TreeView1.Nodes(0).Nodes(i).Nodes(TreeView1.Nodes.Count - 1 + y1).Nodes.Add(ds.Stadt.Rows(z)(0))
    21. 'Me.TreeView1.Nodes(i).Nodes(y).Nodes(z).Tag = ds.Tables(z)
    22. End If
    23. Next
    24. y1 += 1
    25. End If
    26. Next
    27. y1 = 0
    28. Next
    29. Me.TreeView1.Tag = Nothing
    30. Me.TreeView1.ExpandAll()
    31. End If
    32. End Sub

    aber jetzt geht´s in die Koje :whistling:
    Gute Nacht
    Bilder
    • Ergebniss.PNG

      71,23 kB, 1.404×559, 294 mal angesehen

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „CamFreak“ ()

    Hmm - so viele Posts und noch immer auffm falschen Dampfer. Guckma dieses:

    VB.NET-Quellcode

    1. Private Sub TreeViewBefuellen(ds As DatenbankDataSet)
    2. Me.TreeView1.Nodes.Clear()
    3. For Each rwKontinent In ds.Kontinent
    4. Dim ndKontinent = TreeView1.Nodes.add(rwKontinent.KontinentName)
    5. For Each rwLand In rwKontinent.GetLandRows
    6. Dim ndLand = ndKontinent.nodes.add(rwLand.LandName)
    7. For Each rwStadt In rwLand.GetStadtRows
    8. ndLand.nodes.add(rwStadt.StadtName)
    9. Next
    10. Next
    11. Next
    12. Me.TreeView1.ExpandAll()
    13. End Sub

    Das ging wohl an mich. Ich muss gestehen, dass ich mir jetzt erst das Projekt in der Source in Post#1 angeschaut hatte. Habe mich nur am geposteten Code langgehangelt. Hab gestern Abend nicht mehr erwartet, dass das tDS schon korrekt vorbereitet ist, weil immer noch Access-Screenshots zu sehen waren und die Empfohlenen Einstellungen nicht eingestellt waren (z.B. VB6-Namespace entfernen, Option Strict On machen). Die 3fache For-Each hatte ich zwar gestern abend noch vorbereitet, aber dann dachte ich mir, dass das aus. o.g. Falschvermutungen eh nicht hinhaut, weil das tDS noch nicht vernünftig steht. Wurscht, sollte man rechtzeitig posten, bevor der TE auf zu falsche Wege geleitet wird. Hast ja recht. :)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Das gleiche wie der Code von EDR, jedoch ohne die generierten tDs-Klassen (stark typisierten Klassen? - wie nennt man die überhaupt).

    Bedingt jedoch, dass man sich vorher noch die Relationen aus dem Dataset holt.
    Einige Variablen müssen aber trotzdem indexiert angegeben werden, was dem Code ein bisschen an Glanz verlieren lässt.


    VB.NET-Quellcode

    1. Private Sub FillTreeView(ByVal ds As DatenbankDataSet, ByVal MyMdbPathName As String)
    2. If File.Exists(MyMdbPathName) Then
    3. Me.TreeView1.Nodes.Clear()
    4. Dim dt = ds.Tables(0), dsr = ds.Relations
    5. Me.TreeView1.Nodes.Add(New TreeNode(MyMdbPathName))
    6. For Each drcontinent As DataRow In dt.Rows
    7. Dim tncontinent = Me.TreeView1.Nodes(0).Nodes.Add(drcontinent.Item(1).ToString)
    8. For Each drcountry As DataRow In drcontinent.GetChildRows(dsr(0).RelationName)
    9. Dim tncountry = tncontinent.Nodes.Add(drcountry.Item(1).ToString)
    10. For Each drcity As DataRow In drcountry.GetChildRows(dsr(1).RelationName)
    11. tncountry.Nodes.Add(drcity.Item(0).ToString)
    12. Next
    13. Next
    14. Next
    15. Me.TreeView1.ExpandAll()
    16. End If
    17. End Sub


    Freundliche Grüsse

    exc-jdbi