Erweiterter Umgang mit typisiertem DataSet -> Tabellennamen lesen/Namensübergabe etc.

  • VB.NET
  • .NET 4.0

Es gibt 259 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    tragl schrieb:

    genau das hab' ich doch bei allen Datenfeldern
    Hihi - ich hab nur ins Excel geguckt - da sah das anners aus.

    was anners: Im Anhang hab ich mal das MitarbeiterStammdaten-Form ich finde verbessert.
    MitarbeiterStammdatenAuswahl ist nun entbehrlich.
    Man kann glaub damit nun sogar schon neue MA anlegen (hab ich nicht probiert)
    Und löschen natürlich (hab ich nicht probiert)
    Dateien
    Sieht nicht schlecht aus. Wolltest du an dem Dataset noch was machen oder war das "fertig" bzw. OK so? Dann müsste ich die Relationen noch ordentlich setzen - stehen aktuell ja nur auf "nur beziehungen"
    Edit: für's neu Anlegen und löschen würde ich dann lieber Buttons setzen, die kann ich dann über userrechte noch steuern. Das DGV wäre mir dann "ReadOnly" lieber - aber kann man ja alles noch machen
    Originaler (noch) Nichtskönner :D
    nee - das war jetzt nur zur Erklärung, was ich oben weiter so meinte.
    Tatsächlich muss man jetzt die ganze Gui neu machen, weil die DatenObjekte jetzt ja alle annere Namen haben, und die Bindings alle ungültig sind - da grätscht dann der FormDesigner ab.
    Haste schon SolutionExplorer - OpenSource bei dir in Betrieb genommen?
    Damit kannste sehr einfach ein Backup machen.
    Und auch einen Zip bereitstellen zum Posten im Forum.

    Weil Namen-Änderungen am Datenmodell können das ganze Gui irreparabel kaputtmachen - da freut man sich immer über ein Backup.

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

    Das hab ich schon öfter gehabt, man muss dann in der Designer-Datei die Änderungen parallel machen oder die gebundenen Objekte vorher runter nehmen. Kannst du mir das nochmal im Bezug auf Name, Vorname erklären? Du hattest gesagt es sei möglich Relationen mit mehreren Spalten zu definieren.

    Dass das GUI neu muss hab ich mir schon gedacht daher die Frage ob du an dem Dataset noch was ändern würdest, sonst fang ich morgen an das GUI neu zu machen.

    lg und einen schönen Restabend noch :)
    Originaler (noch) Nichtskönner :D




    Zum Datenmodell: Also "" als DefaultValue von String meint, dass du das Eingabefeld im PropertyGrid entleerst - nicht, dass du da "" reinschreibst.
    Aber das wirste auch merken, wenn du mal in eim DGV einen Datensatz zufügst.

    letzteAenderung gehört PascalCase, also LetzteAenderung. Weitere Spalten entsprechend.



    müsste da nicht eine Relation bestehen zw. ProgrammAnsicht und User.Ansicht?

    die beiden DatenAbfrage-Dinger sind fast identisch - kann man das nicht zu einem zusammenfassen?

    Ich versteh das ganze Datenmodell nicht, weil ich die Geschäftsvorfälle nicht kenne.
    Warum gibts da Standorte, aber auch PLZListen, die mir eher aussehen wie TourenStops?




    So prinzipiell reime ich mir was zusammen mit:
    TourenTemplate (das heisst bei dir "Touren")
    Jedes TourenTemplate hat mehrere TourenStops (bei dir "PLZListe")
    Eine Tour (heisst bei dir "Datenabfrage") verknüpft nun einen Mitarbeiter mit einer TourenTemplate und einem Fahrzeug.
    Auf deutsch: Ein Mitarbeiter macht mit einem Fahrzeug eine Tour, entlang der im Tourentemplate ausgewiesenen TourenStops.

    Erscheint mir sinnvoll.

    Ah - Standort könnte der Standort eines Fahrzeugs sein - falls die woanners abgestellt werden als am letzten TourenStop.
    Dann fehlt aber eine Relation StandOrt->Fahrzeug.



    Übrigens: Die beiden Relationen Mitarbeiter->Datenabfrage<-Fahrzeug stellen eine typische m:n-Relation dar zwischen Mitarbeiter und Fahrzeug.
    Hinzu kommt noch Touren->Datenabfrage, also eine m:n:o - Relation.

    Das ist besonders typisch, weil reine m:n-Relationen kommen kaum vor. Immer werden den Mittler-Tabellen zusätzlich zu den FKs noch weitere Spalten hinzugefügt.
    Und auch diese 3-fach-Relation ist nix besonders seltenes.
    Relationale Datenmodellierung ist eben hochflexibel.



    Nochmal zur fehlenden Relation Standort->Fahrzeug.
    Wenn das einfach nur so gemacht wird, dann hat ein Fahrzeug nur einen Standort, und der ändert sich gelegentlich, worüber aber nicht Buch geführt wird.
    Da könnte man sich auch was anderes für ausdenken, dass da eine Historie geführt wird.
    Aber ich merke grad, dass ich dein Standort-Konzept überhaupt nicht verstehe.
    In dem Datenmodell hat ja alles einen Standort: Mitarbeiter (sogar mehrere), Datenabfragen, TourenStops, TourenTemplates, Fahrzeuge.
    Was ist der Sinn?

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Aaalso :)

    Die Datenabfrage(n) müssen unterschiedlich bleiben, die bilden 2 verschiedene Bereiche bei uns ab, auch wenn die sich ähneln.
    Hier werden die "Arbeitsnachweise" eines Mitarbeiters dargestellt. Er trägt ein:

    - Arbeitszeiten
    - Das Fahrzeug mit dem er unterwegs ist + KM-Stände dazu
    - Wieviel Zeit hat er im Lager verbracht usw.

    Damit da nicht irgendein Stuss eingegeben wird, beziehen sich teilweise die Felder auf Parent-Tabellen.

    Das Feld Standort ist überall dazu gedacht, die Datensätze nach eben den Standorten zu filtern bzw. zuzuordnen - was wichtig ist,
    denn viel später kommen noch Auswertungsmodule in die Anwendung rein, die genau das berücksichtigen müssen - also eine
    bei uns genannte "Kennzahlenauswertung". Ich muss also sagen können, "zeig mir alle Einträge aus ... Tabelle ... mit Standort "xy""

    Tabelle "Touren"
    - Beinhaltet unsere Tournummern samt Benamung, welchem Standort zugeordnet etc.

    Tabelle "Fahrzeuge"
    - Stammdaten unserer vorhandenen und aktiven Fahrzeuge

    Tabelle "PlzListe"
    - hier werden einzelne Postleitzahlen den verschiedenen Touren zugeordnet
    Ich muss also in die plzliste reingucken können und nachschauen "ist die Postleitzahl" schon einer Tour zugeordnet. Falls nein, dann die Postleitzahl anlegen und zuordnen.
    Wird also eine reine "Ansicht"-Liste, die die Teamleiter bearbeiten können.

    Das mit dem DefaultValue hab ich verstanden - Die Felder sollen bei Neuanlage leer bleiben, derjenige der neu anlegt kann die aber ja
    mit eigenen Werten überschreiben.

    Zwischen Programmansicht und Useransicht soll keine Relation sein (bzw. die ist indirekt). Dem Mitarbeiter wird eine Funktion
    zugewiesen (Mitarbeiter, TL etc.) - diese Funktionen gelten zeitgleich als Programmansicht und werden dort aus der Tabelle gezogen.
    Wir ein User zu dem Mitarbeiter angelegt (nicht jeder Mitarbeiter wird mit dem Programm arbeiten) dann soll sich die im Mitarbeiterstamm hinterlegte Funktion/Ansicht mit übertragen.

    Alles recht "komplex" aber in meinen Augen sinnvoll und baut auch auf den verschiedensten Excel-Dateien auf, die wir aktuell nutzen.
    Und genau dahinter steckt mein Bestreben: Den ganzen Excel-Müll in ein Programm zusammefassen, weil alles mehrfach am Tag braucht und
    sich jedesmal die Excel-Dateien zusammensucht etc.

    Prinzipiell sind die Tabellen
    - Programmansicht
    - Mitarbeiter
    - Touren
    - Fahrzeuge
    - Standorte

    alles Stammdatentabellen. Die Daten daraus ziehen sich dann weitere Tabellen - ich hoffe, du verstehst was ich damit meine :)
    Originaler (noch) Nichtskönner :D

    ErfinderDesRades schrieb:

    Nein - ich versteh nix, aber macht nix.


    Der Aufbau der Tabellen muss so bleiben - das verlangt unsere Struktur :)
    Wenn ich das neue DataSet eingebaut habe, füll' ich das mal mit ein paar Beispieleinträgen und schick' dir das Projekt nochmal rüber.
    Dann kannst dir vermutlich besser ein Bild davon machen, warum - wieso - weshalb das so sein muss ;)
    Ich probier das dann mal über den SolutionExplorer (lad' ich mir heut abend daheim mal runter)

    ErfinderDesRades schrieb:

    Überlegung allenfalls, ob alle Tabellen mit Standort-Feld nicht auch eine Relation auf Standort haben sollten - damit nicht beliebiger Freitext in den Feldern landet, der später evtl. nicht wiedergefunden wird?



    Eigentlich habe ich alle Standort-Felder mit dem Feld "Standortname" in der Tabelle "Standorte" in Relation gesetzt.
    Originaler (noch) Nichtskönner :D
    dass wenn ich einer Postleitzahl eine Tour zuordne, der im Tourenstamm hinterlegte Standort dahintersteckt.
    Somit kann ich auch auswerten, welche Postleitzahlen gehören zu welchem Standort

    Edit: Mal ne Frage, wie bekomme ich denn bei Zeile 16 mein "my.Settings.Datenverzeichnis" rein?
    Eine Public var bereitstellen ist ja nicht der gewünschte weg - ich hab' in dem Helpermodul keinen Zugriff auf die My.Settings von meinem Projekt

    Originaler (noch) Nichtskönner :D

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

    tragl schrieb:

    dass wenn ich einer Postleitzahl eine Tour zuordne, der im Tourenstamm hinterlegte Standort dahintersteckt.
    Somit kann ich auch auswerten, welche Postleitzahlen gehören zu welchem Standort
    Scheint mir redundant.
    Wenn eine PLZ einer Tour zugeordnet ist, dann kann man über die Relation jederzeit den Standort der zugeordneten Tour abrufen.
    In einem typDataset braucht man dabei nichtmal an die Relation zu denken - weil die typisierung stellt die Verknüpfung ja bereit:

    VB.NET-Quellcode

    1. dim PLZ_Standort = rwPLZ.TourRow.Standort


    Eine zusätzliche Spalte dafür zu schaffen verstösst gegen das Redundanz-Verbot der Datenbänkerei.
    Im Dataset kann man zur Not eine berechnete Spalte schaffen, falls das Gui das unbedingt erfordert. Berechnete Spalten verstossen nicht gegen das Redundanz-Verbot.



    Hmm - vom XmlDatasetAdapter lass besser die Finger. Der kann alles - ist aber höchst komplexer Code.
    Im MainForm.Sub New() weise ich dem Dataset glaub seine Dataset-Datei zu - guck mal nach .DataFile(). Da kannste ihm auch iwas aus deine Settings andrehen.



    Haste die Dataset-Korrekturen fertig?
    Ich würde gerne eine Mainform-Alternative dranmachen, wo die bisherige Anti-OOP- MDI-ChildForm-Behandlung durch eine tabbed-Navigation mit Usercontrols ersetzt ist.
    Wenn du nix dagegen hast.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Okay, das mit der Redundanz muss ich mir dann nochmal genauer angucken, sind dann vermutlich einige Spalten die redundant wären.
    Ich hab' noch ne Frage zu der Speicherei..

    Hab am Tree grad was über das DGV geändert, Änderungen wurden übernommen und beim nächsten Debug-Run waren die Einstellungen wieder weg.
    Liegt das daran, dass VSCE immer ne Kopie der Datei ins Datenverzeichnis schmeißt beim Starten des Debug-Runs?

    Wie kann ich das umgehen? Die XML-Dateien aus dem Projekt "rausnehmen" und in ein entferntes Verzeichnis packen? Möchte die Änderungen gerne immer wieder
    parat haben - es sind ja zur Zeit nur Testeinträge und somit nich schlimm wenn ich mir was zerschieße dabei.
    Originaler (noch) Nichtskönner :D
    (ich weiss nicht, was VSCE ist)
    Ich weiss auch nicht, welche Datei bei dir wohin geschmissen wird. Es gibt im VS DateiEinstellugen, da kann man "Kopieren, wenn neuer" = False einstellen oder sowas.
    Ich würde diese Hoch-Flexiblität mit Settings und so erstmal weglassen.
    Das kannste auch noch dranprogrammieren, wenn ansonsten alles fertig ist.
    Settings scheinen sich ja einfach mal gelegentlich so zu verabschieden.

    Das ist auch immer das erste, was ich bei deim zip ausbaue, weil ich das nicht brauchen kann, da immer nach dem DatenFile zu suchen.
    Ich hab da den relativen Pfad "..\..\Daten\userdata.xml" erstmal festverdrahtet - da weiss ich dann, wo die Datei ist, und auch wenn ichs zippe und dir schicke, ist die Datei da, auch auf deim System.
    Moin.

    ErfinderDesRades schrieb:

    (ich weiss nicht, was VSCE ist)


    VSCE = VisualStudio Community Edition
    Die Datei, die ich meinte ist die Tree.xml, die unter "..\..\Daten\Tree.xml" liegt - diese ist auch in das Projekt eingebunden (über den Projektmappen-Explorer zu sehen).

    Ich bin gerade dabei, die testweise in einen externen Pfad zu verschieben und eine Prüfung draufzulegen, allerdings macht dein "DatasetXmlAdapter.vb" da nicht mit.

    VB.NET-Quellcode

    1. Public Sub New(_Dts As DataSet)
    2. DataSet = _Dts
    3. #If DEBUG Then
    4. DataFile = New FileInfo("..\..\Daten\").Combine(_Dts.GetType.Name & ".xml")
    5. #Else
    6. DataFile = New FileInfo(Application.LocalUserAppDataPath).Combine(_Dts.GetType.Name & ".xml")
    7. #End If
    8. End Sub


    heißt, egal was in der frmMain "registriert" wird

    VB.NET-Quellcode

    1. Dim fi = New FileInfo($"{My.Settings.Datenverzeichnis}\dtsLogistik.xml")
    2. Dts.Register(Me, True).DataFile(fi.FullName).Fill


    juckt im weiteren Verlauf nicht mehr weil es mit den Info's aus dem Helper überschrieben wird.
    Selbst bei Veröffentlichung wäre mein Pfad nicht

    VB.NET-Quellcode

    1. DataFile = New FileInfo(Application.LocalUserAppDataPath).Combine(_Dts.GetType.Name & ".xml")

    sondern eben der, der in einer Auswahl eingestellt und in den Settings gespeichert wird.

    Wie bekomme ich das nun hin, dass ich den Helpers den Pfad aus my.settings übergebe?
    Originaler (noch) Nichtskönner :D
    Echt? Dann habich einen Fehler gemacht - mal guckn.
    Ich bin mir aber sehr sicher, dass du - nach der Registrierung jederzeit das DataFile setzen kannst, wohin du willst, mittels

    VB.NET-Quellcode

    1. Dts.DataFile(<fileName>)

    Hast du mal überprüft, ob dein fi existiert?
    Ich hab da an der Stelle eingefügt:

    VB.NET-Quellcode

    1. If Not fi.Exists Then fi = New FileInfo("..\..\Daten\userdata.xml")
    und das funktioniert.
    Also das überschreibt den Settings-Eintrag, wenn der ungültig war, und dann funktionierts.
    Es gibt keine weitere Stelle, wo das nochmal überschrieben würde.

    Ich hab nu auch Gegenprobe gemacht und den Dateinamen geändert:

    VB.NET-Quellcode

    1. If Not fi.Exists Then fi = New FileInfo("..\..\Daten\userdata2.xml")

    Da erhalte ich wie beabsichtigt die Meldung:

    Brainfuck-Quellcode

    1. ---------------------------
    2. Leider (noch) kein DatenFile vorhanden
    3. Sie können aber trotzdem fortfahren, und eines anlegen.
    4. ---------------------------
    5. OK
    6. ---------------------------
    Also er arbeitet definitiv mit dem DatenFile, was ihm da angegeben wird.



    tragl schrieb:

    Wie bekomme ich das nun hin, dass ich den Helpers den Pfad aus my.settings übergebe?
    Dem Helpers Garnicht.
    Bzw. wie ichs gemacht hab:

    VB.NET-Quellcode

    1. Dim fi = New FileInfo(My.Settings.Datenverzeichnis & "\userdata.xml")
    2. If Not fi.Exists Then fi = New FileInfo("..\..\Daten\userdata.xml") 'tritt nur ein, wenn das aussm my.settings nicht existiert
    3. Dts.Register(Me, True).DataFile(fi.FullName).Fill
    Zeile #3 ist übrigens eine komprimierte Formulierung - kannste auch ausführlicher hinschreiben:

    VB.NET-Quellcode

    1. Dts.Register(Me, True)
    2. Dts.DataFile(fi.FullName)
    3. Dts.Fill




    Aber vmtl. versteh ich grad garnet das Problem.
    Oben schreibst du:

    tragl schrieb:

    Die Datei, die ich meinte ist die Tree.xml, die unter "..\..\Daten\Tree.xml"
    Das ist was anneres, und hat mit meine Helpers nix zu tun.
    Dein Tree-Dingens ist ja iwie was mit einer DataTable - wie du die abspeicherst hab ich keine Aktien drin.
    Ich speichere ein Dataset mitte DatasetHelpers.
    DataTableHelpers zum DataTable-Speichern habichnicht (und würde ich auch von abraten).

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „ErfinderDesRades“ ()

    also bei mir sieht das jetzt so aus

    VB.NET-Quellcode

    1. Public Sub New()
    2. InitializeComponent()
    3. 'TODO Anmeldeformular in den Start einfügen, wo sich der MA erst anmelden muss.
    4. 'nach erfolgreicher Anmeldung werden die My.Settings gesetzt und erst dann der Rest gestartet.
    5. 'Nach Methode dialogresult = OK (was nur nach erfolgreicher Anmeldung der Fall ist)
    6. '
    7. 'Statusbar füllen
    8. #If DEBUG Then
    9. My.Settings.Mitarbeiter_aktiv = "Mitarbeiter, Test"
    10. My.Settings.Mitarbeiter_Funktion = "TL"
    11. My.Settings.Mitarbeiter_Standort = "Teststandort"
    12. #End If
    13. 'Datenverzeichnis prüfen
    14. If Not Directory.Exists(My.Settings.Datenverzeichnis) Then
    15. msgExclamation("Datenverzeichnis ungültig, bitte auswählen!")
    16. Using fldBrowse As New FolderBrowserDialog()
    17. If fldBrowse.ShowDialog() = DialogResult.OK Then
    18. My.Settings.Datenverzeichnis = fldBrowse.SelectedPath
    19. My.Settings.Save()
    20. Else
    21. msgError("ungültiger Datenpfad, Anwendung wird beendet!")
    22. AppBeenden()
    23. End If
    24. End Using
    25. End If
    26. 'DataSetFile prüfen
    27. Dim fi = New FileInfo($"{My.Settings.Datenverzeichnis}\dtsLogistik.xml")
    28. Dts.Register(Me, True).DataFile(fi.FullName).Fill
    29. If Not fi.Exists Then fi = New FileInfo("..\..\Daten\userdata.xml")
    30. If Not fi.Exists Then
    31. msgExclamation("Datendatei "" dtsLogistik.xml "" ungültig, bitte auswählen")
    32. Using fiDlg As New OpenFileDialog()
    33. fiDlg.InitialDirectory = My.Settings.Datenverzeichnis
    34. fiDlg.Filter = "Datendateien (*.xml)|*.xml"
    35. If fiDlg.ShowDialog() = DialogResult.OK Then
    36. fi = New FileInfo(fiDlg.FileName)
    37. Else
    38. msgError("ungültige Datendatei ausgewählt, Anwendung wird beendet!")
    39. AppBeenden()
    40. End If
    41. End Using
    42. End If
    43. 'TreeFile prüfen
    44. fi = New FileInfo($"{My.Settings.Datenverzeichnis}\dtsTree.xml")
    45. If Not fi.Exists Then
    46. msgExclamation("Datendatei "" dtsTree.xml "" ungültig, bitte auswählen")
    47. Using fiDlg As New OpenFileDialog()
    48. fiDlg.InitialDirectory = My.Settings.Datenverzeichnis
    49. fiDlg.Filter = "Datendateien (*.xml)|*.xml"
    50. If fiDlg.ShowDialog() = DialogResult.OK Then
    51. fi = New FileInfo(fiDlg.FileName)
    52. Else
    53. msgError("ungültige Datendatei ausgewählt, Anwendung wird beendet!")
    54. AppBeenden()
    55. End If
    56. End Using
    57. End If
    58. dtsTree.dts_Tree.Register(Me, True).DataFile(fi.FullName).Fill
    59. dtsTree.dts_Tree.FillTree(TV_main)
    60. 'If Not fi.Exists Then fi = New IO.FileInfo("..\..\Daten\dtsTree.xml")
    61. Me.TSS_main_lbl_tageskontrollblätter.Text = "Tageskontrollblätter mitführen bis einschl.: " & Date.Today.AddDays(-28)
    62. End Sub
    63. Public Sub AppBeenden()
    64. My.Settings.Save()
    65. Application.Exit()
    66. End Sub


    Ist die Datei im Datenverzeichnis nicht vorhanden, dann öffnet er einen FileDialog, wo die Xml ausgewählt werden soll.
    Die Auswahl setzt er als neue "fi" und danach wird die registriert.
    Dennoch zieht er sich immer wieder "..\..\Daten\xmldatei" aus deinem Helper. Das lässt sich auch über Haltepunkte und Schritte via F11 nachvollziehen.

    Deshalb such' ich nach einer Möglichkeit, den Part in "DataXmlAdapter.vb" wegzulassen und das anders zu regeln - bzw.
    ihm den "fi" ordentlich zu übergeben.

    VB.NET-Quellcode

    1. Public Sub New(_Dts As DataSet)
    2. DataSet = _Dts
    3. #If DEBUG Then
    4. DataFile = New FileInfo("..\..\Daten\").Combine(_Dts.GetType.Name & ".xml")
    5. #Else
    6. DataFile = New FileInfo(Application.LocalUserAppDataPath).Combine(_Dts.GetType.Name & ".xml")
    7. #End If
    8. End Sub
    Originaler (noch) Nichtskönner :D
    Es gibt ja 2 Datendateien, und ich weiss nicht, bei welcher das Problem auftritt.
    Tatsächlich sind in deim Code sogar 3 Dateien erwähnt:
    • dtsLogistik.xml
    • userdata.xml
    • dtsTree.xml
    Welche von denen macht das Problem?

    Ich hab jetzt auch noch geguckt, und fand, dass ich deine Tabellen-Laderei ausgebaut hatte - also meine DatasetHelpers befüllen nu auch dein dtsTree.
    Allerdings funzt das.

    ah - ich glaub habs - frmTreeSettings ist nicht registriert.
    Also probierma:

    VB.NET-Quellcode

    1. Imports Logistik_Tool.dtsTree
    2. '...
    3. Public Class frmTreeSettings
    4. Public Sub New()
    5. InitializeComponent()
    6. dts_Tree.Register(Me, False)
    7. End Sub
    Jo - schönes Beispiel für formübergreifendes Databinding - wenn mans unterlässt.

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich schau gleich nach und hau den Tree mit ins große DataSet dann gibt’s nur eins. Muss ich mir dann mit Updates usw. überlegen wie ich das später mal anstelle. Dann gibt’s auch nur ein Datafile und dann sollte das passen :)

    melde mich, falls das nicht klappt
    Originaler (noch) Nichtskönner :D