Fragen zu Dataset->Db

  • VB.NET

Es gibt 51 Antworten in diesem Thema. Der letzte Beitrag () ist von OliverSte.

    Ok, das habe ich absichtlich gemacht. Aus Gründen der "Komponenten-Sparsamkeit". Wir ja sicherlich immens viel Code im Hintergrund generiert.
    Ich probier das aus und geb Bescheid. Danke für deine Hilfe <3
    Nein, das war nicht das Problem. Auch mit neu erstellten BindingSourcen für die Comboboxen klappt es nicht :(

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

    OliverSte schrieb:

    Ich lege einen neuen Mitarbeiter an (ID=-1) und einen neuen Termin mit diesem Mitarbeiter.
    Beim Speichern kommt die Ausnahme "Der DataGridViewComboBoxCell-Wert ist ungültig."
    Da hab ich auch nix anderes erfunden als du bislang machst: das DataError-Ereignis behandeln.
    Statt eine Messagebox ausgeben halt nix ausgeben, dann tut das nix.
    Grund ist, dass während Abspeichern zwangsläufig kurzzeitig ein unzulässiger Zustand eintritt, wenn der Parent-Datensatz bereits auf den neuen PK umgestellt hat, der Child-Datensatz aber noch nicht.
    Die Relation hat schon UpdateRule.Cascade eingestellt, oder?
    Ja, hab ich.
    Die Löschweitergabe ist für mein Projekt nicht akzeptabel. Es muss verhindert werden, dass beim Löschen von Mitarbeitern die Termine mit rausfliegen. Dazu ist der Mechanismus auch gedacht. Also stelle ich die Löschregel wieder auf "None", was in MySQL "Restrict" entspricht.
    Nun passiert wirklich merkwürdiges.
    1. Ich lösche den Termin eines MA, alles ok. Ich lösche diesen Mitarbeiter, auch ok. Beim Persisitieren knallts.
    Würde ich nach dem Löschen des Termins persisitieren, dann erst den MA löschen, klappt's. Ist ja auch klar, da die Save() Routine offenbar erst die Parenttables updated und erst dann die Childs. Ginge es auch anders herum?

    2. Ich versuche den MA zu löschen und bekomme die Exception. So soll das. Dann lösche ich halt den Termin, doch die Zeile bleibt im DGV stehen und es hagelt Exceptions "Der Index 4 hat keinen Wert.".
    Das Ereignis UserDeletingRow wird gefeuert, UserDeletedRow aber nicht mehr. Wo bleibt das Teil wohl hängen?
    Wenn ich dann einfach "Speichern" klicke, also persisitiere, wird das DGV schön aktualisiert und alles ist gut.

    Also dein Tipp, ignorier die Exception einfach, hilft hier nicht, weil die Zeile stehen bleibt.
    Idee?
    Bilder
    • Persistieren nach Löschen eines Termins und MA.jpg

      122,53 kB, 837×371, 31 mal angesehen

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

    Ich bestätigte, dass ich die UpdateRule.Cascade eingestellt hatte.

    Zusätzlich sagte ich, unabhängig von Zeile 1, dass ich keine Löschweitergabe wünsche. Klar, das hat mit der UpdateRule gar nichts zu tun. Es ist auch egal, was sich da einstelle. Die IDs ändern sich nämlich nicht.

    Ich habe deinen Persistieren Code etwas verändert, nämlich eine RankedTable2 Liste erstellt, in der die Childs vorne stehen. Ob ich es richtig gemacht habe, weiß ich nicht. Diese nutze ich dann im Save() für die Deletions. Das klappt soweit :-D. Müsste man irgendwie parametrisieren, je nach Löschregel. Aber erst mal egal.

    Leider bleibt das davon unabhängige (weil es vor dem Persistieren auftritt) Problem, dass beim Löschen der Zeile diese im DGV stehen bleibt.
    also dass ich das Problem richtig verstehe:
    Der User soll erst alle Termine löschen können und dann den Mitarbeiter.
    Aber er darf nicht den Mitarbeiter löschen können derart, dass die Löschweitergabe die Termine abräumt?

    Das geht nicht outofthebox.
    Meine generelle Strategie ist Löschweitergabe, und wenn das in Einzelfällen nicht recht ist, muss man iwie eine Extrawurst programmieren.
    Die übliche Ausnahme von meiner Strategie ist, dass aus einer Tabelle garnicht gelöscht werden darf, dann stellt man das einfach am DGV ein.
    Aber Löschen erlauben, jedoch nur bei denen, wo keine Child-DAtensätze vorhanden sind, dassis Extrawurst - würde ich dann auch nicht über die Standard-Grid-Löschung machen, sondern Extra-Button einführen, die dann vlt. disabled sein können oder sowas.
    Ja, ich glaub inzwischen, es ist durchaus möglich, bei Löschungen die Reihenfolge umzudrehen. Ist zwar weniger effizient, als wenn die DB sich selbst um Löschweitergabe kümmert, aber dass sich deswegen Fehler einstellen fällt mir grad nicht ein.
    Dann kann man das temporäre Umstellen der AcceptRejectRules auch weglassen, also den Kram mit _ForeignKeyStatui

    VB.NET-Quellcode

    1. Public Sub Save()
    2. ' process all tables twice, the second time in reversed ranked order. First select and update Addeds and Modifieds
    3. _Dts.AcceptVirtualChanges()
    4. Using Connection_EnterOpen()
    5. Const AddedsAndModifieds = DataViewRowState.Added Or DataViewRowState.ModifiedCurrent
    6. _RankedTables.ForEach(Sub(tb) GetAdapter(tb).Update(tb.Select("", "", AddedsAndModifieds)))
    7. DirectCast(_RankedTables, IEnumerable(Of DataTable)).Reverse.ToList.ForEach(Sub(tb) GetAdapter(tb).Update(tb)) ' update Deleteds
    8. End Using
    9. End Sub
    ungetestet

    Dass beim Löschen einer Zeile diese im DGV bestehen bleiben würde konnte ich nicht reproduzieren

    ErfinderDesRades schrieb:

    bei Löschungen die Reihenfolge umzudrehen

    Ich hab bei mir auch nur 2-3 Tabellen mit Löschweitergabe (und du weißt, das ich seeehr viele Tabellen habe :) ) Wäre es in bestimmten Anwendungsfällen nicht sogar absolut sinnvoll,
    erst die Childs und dann Parents beim Löschen zu berücksichtigen? Dann könnte man sich an einigen Stellen sicher das "Zwischenspeichern" sparen. Wenn Ich z.B. aus einer Bestellung die Positionen lösche,
    dann muss ich erst saven, bevor ich die Bestellung selbst löschen kann.

    Würde ich zumindest sinnvoll finden. Werd' ich sicher nicht mehr umbauen, weil so jetzt alles funktioniert aber für künftige Projekte wär' das ganz gut.
    z.B. du hast ein Unternehmen mit sehr vielen Mitarbeitern und die haben noch mehr Termine. Dann geht irgendein Futzie her und löscht den Mitarbeiter samt
    den Terminen, obwohl manche davon noch in der Zukunft liegen und vom Nachfolger abgearbeitet werden müssen - oder die Termine müssen bleiben wegen
    Archiv etc.

    Wenn die Löschweitergabe verhindert wird, dann hat dieser Futzie sehr viel mehr Arbeit, denn er muss erstmal alle Childs raussuchen und löschen und dann erst den Mitarbeiter. Das schreckt sicher
    ab und verhindert auch versehentliches Chaos. Deshalb arbeite ich bei mir eigentlich ausschließlich mit "Aktiv/Inaktiv". Wenn ein Mitarbeiter geht dann wird er "deaktiviert" und fertig. Man kann aber
    im Nachgang noch alles einsehen. Ist sicher für die Datenbank irgendwann grauenhaft, da müsste man sich dann mal ein Archivierungssystem überlegen was solche Einträge mit Childs in eine Art
    "Archiv-Datenbank" packt. Edit: Mir fällt grad ein, dazu mach ich bestimmt bald mal einen Thread auf - der wird sicher interessant. BIn ja schon am überlegen, wie ich das am sinnvollsten anstellen könnte ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    ErfinderDesRades schrieb:

    Ja, ich glaub inzwischen, es ist durchaus möglich, bei Löschungen die Reihenfolge umzudrehen. Ist zwar weniger effizient, als wenn die DB sich selbst um Löschweitergabe kümmert, aber dass sich deswegen Fehler einstellen fällt mir grad nicht ein.


    Ohh, das ist ein schöner Ansatz. Ich habe nach etwas wie Reverse gesucht, aber in List nicht gefunden. Einfach Umcasten nach Aufzählung, klasse :D
    Das funktioniert. Ich muss im Dataset die UpdateRule auf Cascade setzen, damit die neue ID beim Speichern übernommen wird.


    Dass beim Löschen einer Zeile diese im DGV bestehen bleiben würde konnte ich nicht reproduzieren


    Hmm, das ist aber komisch. Bitte stell im Dataset als Beziehungstyp mal "None" ein. Dann versuche zunächst einen MA zu löschen und klicke die Meldung weg. Dann lösche den Termin dazu. Die Zeile bleibt stehen. Bewegst du nun die Maus über das DGV, werden die Felder geleert und Exceptions geworfen (die ich ignoriere, stehen aber im Direktfenster).

    Ich hab das mal eben gefilmt: share.icloud.com/photos/0b2JBsKAk5SfjKRtPa6gdDnEw

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

    Puh!
    Durch den abgebrochenen Delete-Vorgang entfällt das .RowDeleted-Event.
    Darin aber findet aber das Aufräumen einer Lösch-Weitergabe-Optimierung statt, und wenn das unterbleibt fangen die Bindingsources das Spinnen an - klar soweit?

    Bugfix also:

    VB.NET-Quellcode

    1. Private Sub _RowDeletingOrDeleted(sender As Object, e As DataRowChangeEventArgs) Handles _ActiveTable.RowDeleting, _ActiveTable.RowDeleted
    2. 'since subscribed both events it toggles 2 times, and everything is as before ;)
    3. 'when RowDeleting fails, .RowDeleted will not fire. Then the toggle-back call must be triggered by BusyDelay
    4. If _FloodFillFlag Then
    5. 'unsubscribe BusyDelay since RowDeleted was fired properly
    6. BusyDelay.RemoveCallback(AddressOf ToggleChildBindingSources)
    7. Else
    8. BusyDelay.SetCallback(AddressOf ToggleChildBindingSources)
    9. End If
    10. ToggleChildBindingSources()
    11. End Sub
    Ja, völlig klar. Ich hatte das von Anfang an gewusst und wollte dich nur testen :D
    Super, hab's eingebaut und getestet. Klappt wunderbar. Danke sehr!
    Aber sag mir mal, bin ich komisch, weil ich so einen Fehler finde?

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