DataSet: Neuen Datensatz erstellen

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von VB1963.

    DataSet: Neuen Datensatz erstellen

    yo Leute,

    irgendwie raff ich es nicht, wie ich bei einem typisierten DataSet einen neuen Datensatz erstellen kann. (Über einen Button)
    Gegeben ist ein Dataset (Screenshot). Zu Testzwecken absichtlich schlicht gehalten (ID ist Primkey, Autoincrement True; 2 anderen Spalten String)
    Ich will jetzt in der Form, dass wenn ich auf "Neu" klicke alle Textboxen geleert werden und ich meinen neuen Datensatz quasi genereieren kann.
    Nach Drücken auf "Speichern" soll der Datensatz eventuell noch geprüft und anschließend halt gespeichert werden.
    Wähle ich dann links in der Listbox einen (anderen) Datensatz aus wird mir dieser dann in den Textboxen angezeigt.
    Ändere ich was und klick auch auf "Speichern" soll dieser Datensatz natürlich gespeichert werden.

    Würd ich das ganze über ein DataGridView machen kann ich ja in der letzen Zeile einen neuen Datensatz anlegen (hier macht er das ja auch richtig).
    Wie jedoch muss ich es angehen, wenn ich dies über einen Button machen will? (find ich einfach schöner wenn man auf "neu" klicksen kann)

    BTW: Die Listbox links zeigt die Nachnamen der Datensätze an und ist mit einer Bindingsource an das Dataset gebunden. Bei den Textboxen ist die "Text" Property per DataBinding an die BindingSource gebunden.

    lg
    Bilder
    • DataSetKontakt.PNG

      3,12 kB, 154×97, 3.466 mal angesehen
    • DataSetForm.PNG

      7,81 kB, 379×194, 364 mal angesehen
    • DataSetBindingSource.PNG

      17,91 kB, 419×265, 345 mal angesehen
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Wie navigierst Du denn eigentlich zwischen den Datensätzen?

    Ungeprüft:

    VB.NET-Quellcode

    1. Dim dtNewRow As DataSet.KontaktRow
    2. dtNewRow = Me.DataSet.Kontakt.NewKontaktRow
    3. dtNewRow.Item("Nachname") = DBNull.Value 'oder "<Nachname>"
    4. dtNewRow.Item("Vorname") = DBNull.Value
    5. DataSet.Kontakt.AddKontaktRow(dtNewRow)


    Wie DataSet bei dir wirklich heißt weiß ich natürlich nicht.
    keine Ahnung - bei mir aktualisieren sie sich.
    kannstes jamal lauffähig gezippt anhängen.

    Oder du untersuchstes selbst. In Viele DbSamples sind glaub einige Samples auch mit Comboboxen zu finden - Combo- und Listbox sind Datenbänkerisch identisch.
    Da muß sich iein Unterschied zu deinem Werk finden lassen.

    ErfinderDesRades schrieb:

    such im ObjectBrowser nach der Klasse KontaktDataTable, und guck dir die dortigen Methoden an.
    Es sind mehrere Add-Varianten vorhanden, und bei einer kann man die neuen Werte gleich angeben.

    Der untypisierte Zugriff von HaroWagner ist umständlich und unsicher.
    Ich würde ja gerne lernen und mich verbessern, wenn ich es denn könnte, kann ich aber nicht. Mag sein ich bin zu blöd dazu. Den Eindruck vermittelst Du mir jedenfalls.



    Das ist die einzige Möglichkeit, die ich über den Objektkatalog (einen ObjectBroswer hat meine IDE nicht) gefunden habe.
    Ich habe mir nun diese Samples durchgeschaut und bin denk ich beim Fahrtenbuch auf die Lösung gestoßen.
    Hab es nun Zuhause am 2012er nachgebaut. (gleich wie die Screenshots oben)

    VB.NET-Quellcode

    1. Private Sub btnNeu_Click(sender As Object, e As EventArgs) Handles btnNeu.Click
    2. KontaktBindingSource.AddNew()
    3. End Sub
    4. Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    5. KontaktBindingSource.EndEdit()
    6. KontaktBindingSource.ResetItem(KontaktBindingSource.Position)
    7. End Sub


    Hier wird ein neuer Datensatz erstellt (auch die Felder alle geleert :) ). Er schreibt in das Readonly Textböxchen auch gleich die nächste ID.
    Wird der Eintrag gespeichert wird die Listbox aktualisiert. Beende ich das Programm und verwende die Speichermethode wie im Fahrtenbuch ("allgemein verwendbare Funktionalität") speichert er mir die Daten richtig ins xml und lädt es auch beim Start wieder :)

    Ist nochwas zu beachten oder kann ich mich mal so darauf stürzen und das Testprojekt mit mehreren Tables erweitern?

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    HaRoWagner schrieb:

    Mag sein ich bin zu blöd dazu. Den Eindruck vermittelst Du mir jedenfalls.
    Sorry - mit Sozialkompetenz bin ich überfordert.
    Ich halte niemanden für blöd, ausser ich bekomme das Gefühl, gegen eine Wand zu reden. Und auch diese Leuts (also die zielführende Beiträge ignorieren) sind nicht unbedingt blöd, höchstens zu blöd um nachzufragen, wenn sie was nicht verstehen. (naja - vlt. sind sie doch auch blöd - gibt immer solche und solche)
    Jdfs. dich halte ich ganz ganz sicher nicht für blöd. :thumbsup:
    Ich sag aber einfach immer, wie ich finde, dasses ist, und nehme keine Rücksicht auf Empfindlichkeiten, weil ich durchs Internet keine Empfindlichkeiten wahrnehmen kann.
    Also wenn ich eine bessere Lösung weiß, dann sag ich einfach, dass die annere Lösung schlechter ist - deswegen ist niemand blöd.
    Generell binnich dafür, Forenposts ganz streng sachlich zu lesen, und auf emotionale Interpretationen möglichst komplett zu verzichten, weil die Info-Basis für derlei Interpretationen ist viel zu dünn.
    Um die Beziehungsebene einer Botschaft auch nur leidlich richtig zu empfangen braucht man einen realen Menschen leibhaftig gegenüber, und den muss es auch noch einigermaßen kennen - alles annere grenzt meist an Einbildung, findich.

    ObjectBrowser und ObjektKatalog ist dasselbe - Browser ist glaub die engl. Bezeichnung.

    Und du hast doch die richtige Methode gefunden - genau die meinte ich!
    Damit kannst du in einer Zeile deiner KundenDataTable eine KundenRow zufügen.
    Einfach hinschreiben, und einen erforderlichen Parameter nach dem anneren eintragen. Das ergibt eine ziemlich lange Zeile, aber ist besser als die vielen Zeilen, die du vmtl. derzeit hast.
    Du kannst auch mal deinen derzeitigen AddKunde-Code posten, und ich schreib den um, dann sieht man die Vorzüge ziemlich klar.




    @fichz:: guck - das BindingSource.AddNew hatte ich jetzt ganz vergessen - dassis natürlich am schicksten :thumbsup:

    Den Save-Button verstehe ich nicht - saven tut der ja nicht, sondern beendet und übernimmt nur eine Eingabe (statt sie zu canceln).

    Naja, wg. weitere Tables: natürlich kannst du, und zu beachten sind nur die allgemeinen Regeln der Datenmodellierung.
    Ach - und bei mir hat sich ein Benamungsschema rausgebildet, ja gut, also ist schon einiges zu beachten, um eine optimale Architektur zu erhalten: mein Benamungs-Schema für DB-Entitäten
    @ErfinderDesRades: Bei mir heißt er btnSave. Bei deinem Projekt halt btnOk :P
    Unter Save Button mein ich einfach, dass der User diesen Datensatz abschließen kann. Und das macht er damit in dem er diesen halt speichert.
    Es gibt auch eine Methode BindingSource.CancelEdit. Ich hab diese noch nicht probiert nur ich vermute mal stark, dass das Gegenteil vom BindingSource.EndEdit ist (nämlich den Datensatz verwerfen)

    Ich finde es einfach von der Useability her besser wenn der User weiß was mit dem Datensatz gerade passiert (speichern/verwerfen).
    Abschließend, kann er dann ja das Gesamte geänderte in das xml File/Datenbank abspeichern.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Hab nun noch eine Frage was denk ich zu dem Thread noch passt.

    Ich habe nun testweise die Spalte Nachname als "AllowDBNull" False gekennzeichnet.
    Versuche ich nun einen neuen Satz ohne Nachname zu speichern wirft mir die EndEdit Methode eine Exception um die Ohren.

    Nun dachte ich mir, ich prüfe einfach ob die Felder des aktuellen Datensatzes korrekt ausgefüllt wurden.

    zB.:

    VB.NET-Quellcode

    1. If CheckEntry() Then
    2. KontaktBindingSource.EndEdit()
    3. KontaktBindingSource.ResetItem(KontaktBindingSource.Position)
    4. Else
    5. MessageBox.Show("Es wurden nicht alle Pflichfelder ausgefüllt!", "Fehler beim Übernehmen", MessageBoxButtons.OK, MessageBoxIcon.Error)
    6. End If
    7. Private Function CheckEntry() As Boolean
    8. Dim fSuccess = True
    9. Dim dataRow = DirectCast(DirectCast(KontaktBindingSource.Current, DataRowView).Row, dsMain.KontaktRow)
    10. ErrProvMain.Clear()
    11. ' Nachname prüfen
    12. If dataRow.IsNull(DsMain.Kontakt.NachnameColumn) Then
    13. ErrProvMain.SetError(txtNachname, "Nachname darf nicht leer sein")
    14. fSuccess = False
    15. End If
    16. Return fSuccess
    17. End Function


    Das ist denk ich bei einem Feld zu prüfen kein Problem. Jedoch kann sich diese Funktion ziemlich verkomplizieren wenn hier mehr geprüft werden muss (viele Felder, Feldlängen, ...)

    Gibt es dazu nicht eine einfachere Möglichkeit?
    die "datarow" hätte eine "HasError" Property welche jedoch auf false steht (obwohl bei datarow.Nachname es schon die Exception drin steht).

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Das ist doch ein überaus nützliches Feature!
    Es hat doch keinen Sinn, einen Kunden ohne Nachnamen anzulegen.
    Ich hab fast nie AllowDBNull, weil inne Datenverarbeitung nervt das, immer erst prüfen zu müssen, ob der Wert ühaupt gesetzt ist, bevor man ihn abrufen kann.

    Meist lege ich einen Default-Value fest - dann kann DBNull garnet auftreten.
    Naja ich glaube du hast mich da missverstanden.
    Klar ist das nützlich. Gibt es aber eine einfachere Möglichkeit ob dieser Datensatz alle "Anforderungen" erfüllt ausser dies in einer eigenen Methode zu prüfen. Da die Steuerelemente ja an der Bindingsource hängen dachte ich mir, dass es vielleicht irgendeine Überprüfungsmethode der BindingSource/DataRow/etc... geben könnte.

    Die mir einfach sagt ob der Datensatz jetzt so gespeichert werden kann oder nicht.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    also es gibt folgendes:
    • AllowDbNull: nicht-gesetzte Werte sind zulässig
    • DefaultValue: nichtgesetzte Werte können garnet auftreten, weil ja immer der Default gesetzt wird.
    Weitere Zulässigkeiten musst du selbst abprüfen, in einer eigenen Methode. Hierfür ist das Validating-Event zuständig, gugge Control.Validating + ErrorProvider
    Validierung ist eine eigene Wissenschaft, und kann beliebig komplex werden.
    Und es gibt da auch noch einen Regel-basierten Ansatz - gugge etwa IDataErrorInfo

    fichz schrieb:

    Ich will jetzt in der Form, dass wenn ich auf "Neu" klicke alle Textboxen geleert werden und ich meinen neuen Datensatz quasi genereieren kann.
    Dann mach es doch einfach mit Me.KontaktBindingsource.AddNew(). Hilfreiche Links hat Dir der ErfinderDesRades auch schon zugesendet... Es gibt viele verschiedene Lösungen, Du musst nur die für Dich beste herausfinden. :)
    @fichz:
    Die Eingabeüberprüfung der Daten im DGV kann man auch in der zu grunde liegenden Tabelle machen und die Tabellenereignisse dazu verwenden...
    Siehe unten grob angegebenes Schema:

    VB.NET-Quellcode

    1. 'Eingabeprüfung unmittelbar nach Zeilenwechsel...
    2. Private Sub DeineDataTable_DeineDataTableRowChanging(sender As Object, e As DeineTabelleRowChangeEvent) Handles Me.DeineDataTableRowChanging
    3. If Not (e.Action = DataRowAction.Change OrElse e.Action = DataRowAction.Add) Then Return
    4. RemoveHandler Me.DeineDataTableRowChanging, AddressOf DeineDataTable_DeineDataTableRowChanging
    5. Select Case True
    6. Case e.Column Is DeineErsteColumn
    7. 'Eingabe überprüfen, und bei Fehlerfall SetColumnError setzen ...
    8. e.Row.SetColumnError(DeineErsteColumn, "Deine Fehlermeldung !")
    9. Case ... 'nächste Column usw.
    10. End Select
    11. '
    12. If e.Row.HasErrors Then
    13. 'eine Exception auslösen
    14. 'Fehlerbehandlung geschieht in der Form im Zuge des DGV.DataError-Event
    15. End If
    16. AddHandler Me.DeineDataTableRowChanging, AddressOf DeineDataTable_DeineDataTableRowChanging
    17. End Sub
    18. 'Eingabeprüfung unmittelbar nach Spalteneingabe...
    19. Private Sub DeineDataTable_ColumnChanging(sender As Object, e As System.Data.DataColumnChangeEventArgs) Handles Me.ColumnChanging
    20. If Not {DeineErsteColumn, ... }.Contains(e.Column) Then Return
    21. RemoveHandler Me.ColumnChanging, AddressOf DeineDataTable_ColumnChanging
    22. Select Case True
    23. Case e.Column Is DeineErsteColumn
    24. 'Hier den Wert auf Richtigkeit prüfen
    25. 'entweder wie oben SetColumnerror setzen und erst verzögert im RowChanging-Event eine Exception auslösen
    26. 'oder sofort eine Exception auslösen
    27. 'Fehlerbehandlung geschieht in der Form im Zuge des DGV.DataError-Event
    28. Case ... 'nächste Column usw.
    29. End Select
    30. AddHandler Me.ColumnChanging, AddressOf DeineDataTable_ColumnChanging
    31. End Sub

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „VB1963“ ()