Dataset und Transaktionen

17/02/2009 - 20:43 von Armin Zingler | Report spam
Hallo miteinander,

ich habe in einem Dataset eine Master- und eine Detailtabelle. Der Benutzer
kann in einem Formular einen Mastersatz und zugehörige Detailsàtze àndern.
Ein Feld der Detailtabelle ist der Primàrschlüssel und kann vom Benutzer
selbst eingegeben werden. Das Eingabeformular hat einen Save-Button, wodurch
der Master- und die Detailsàtze per OleDbDataAdapter.Update in der Datenbank
gespeichert werden.

Da der Benutzer den PK der Detailtabelle selbst eingeben kann, kann es zum
Fehler beim Speichern (Insert) aufgrund von Duplikaten kommen. Zuverlàssig
kann dieser Fall (aufgrund Multiuser-Betrieb) nur durch Abfangen der
Exception beim Insert abgefangen werden. Da alle Daten im Formular als eine
Einheit zu sehen sind, soll auch der Benutzer eindeutig wissen: Daten wurden
gespeichert oder nicht. "Daten wurden teilweise gespeichert" wàre keine
akzeptable Meldung.

Wie wird denn diesem Umstand bisher Rechnung getragen? Ist das irgendwie
vorgesehen? Gibt es außer der Verwendung von Transaktionen
(oledbconnection.begintransaction), also Beginn vor dem Update und
Commit/Rollback danach, eine andere eingebaute Möglichkeit? (ich glaube ja
eher nicht...) Mein Hauptproblem ist aber: Selbst wenn ich den
Speichervorgang in eine Transaktion stecke: Davon bekommt das Dataset ja
nichts mit! Das heißt: Durch das AcceptChanges wurden schon Änderungen im
Dataset vollzogen obwohl diese aufgrund des anschließenden Rollbacks ja gar
nicht stattgefunden haben. (wenn z.B. die Exception erst beim 3. Satz
auftritt)

Als Lösung sehe ich derzeit nur, die gesamte Logik, die in
OleDbDataAdapter.Update steckt, durch eigenen Code zu ersetzen. Er würde
sich nur dadurch unterscheiden, dass AcceptChanges nicht pro verarbeiteter
DataRow aufgerufen wird. Stattdessen würde AcceptChanges erst dann
aufgerufen, wenn vorher _alle_ Sàtze erfolgreich geschrieben werden konnten.
Ist das eine "übliche" Vorgehensweise? Ich meine, auf die Situation, dass
ein Update für mehrere Sàtze innerhalb einer Transaktion erfolgen muss
stosse ich ja nicht als erster Mensch überhaupt. ;-)

So, schon ma danke fürs Lesen. Kürzer kann ich nicht. :)

Armin
 

Lesen sie die antworten

#1 Peter Fleischer
18/02/2009 - 07:22 | Warnen spam
"Armin Zingler" schrieb im Newsbeitrag
news:%

ich habe in einem Dataset eine Master- und eine Detailtabelle. Der
Benutzer
kann in einem Formular einen Mastersatz und zugehörige Detailsàtze àndern.
Ein Feld der Detailtabelle ist der Primàrschlüssel und kann vom Benutzer
selbst eingegeben werden.



Hi Armin,
prinzipiell sollte der Primàrschlüssel vor dem Anwender versteckt werden
oder mindestens als "Nur Lesen für den Anwender" genutzt werden. Der
Primàrschlüssel sollte ausschließlich für die Sicherung der Konsistenz der
Daten in der Datenbank dienen. Wenn das nicht so gemacht wird, wird der
gesamte Prozess erschwert und erfordet einen nicht unerheblichen
zusàtzlichen Aufwand, wie du ja bereits bemerkt hast.

Das Eingabeformular hat einen Save-Button, wodurch
der Master- und die Detailsàtze per OleDbDataAdapter.Update in der
Datenbank
gespeichert werden.

Da der Benutzer den PK der Detailtabelle selbst eingeben kann, kann es zum
Fehler beim Speichern (Insert) aufgrund von Duplikaten kommen.



Genau das ist keine gute Idee. Daten sollten unabhàngig von internen
Organisationskriterium bearbeitet werden. Wenn die Daten unikat sein sollen,
dann kann man das mit einem Constraint in der Datenbank lösen. Das kann dann
zwar auch einen Duplicate-Fehler auslösen, die Daten bleiben aber
konsistent.

Zuverlàssig
kann dieser Fall (aufgrund Multiuser-Betrieb) nur durch Abfangen der
Exception beim Insert abgefangen werden. Da alle Daten im Formular als
eine
Einheit zu sehen sind, soll auch der Benutzer eindeutig wissen: Daten
wurden
gespeichert oder nicht. "Daten wurden teilweise gespeichert" wàre keine
akzeptable Meldung.



Du kannst doch das Speichern beim Fehlerfall abbrechen
(ContinueUpdateOnError=False, was Standardeinstellung ist).

Wie wird denn diesem Umstand bisher Rechnung getragen?



Abbrechen bei Fehler.

Ist das irgendwie
vorgesehen?



ContinueUpdateOnError=False

Gibt es außer der Verwendung von Transaktionen
(oledbconnection.begintransaction), also Beginn vor dem Update und
Commit/Rollback danach, eine andere eingebaute Möglichkeit? (ich glaube ja
eher nicht...)



Transaktionen sichern gegen parellen Zugriff, nicht gegen eigene
Fehlablàufe.

Mein Hauptproblem ist aber: Selbst wenn ich den
Speichervorgang in eine Transaktion stecke: Davon bekommt das Dataset ja
nichts mit! Das heißt: Durch das AcceptChanges wurden schon Änderungen im
Dataset vollzogen obwohl diese aufgrund des anschließenden Rollbacks ja
gar
nicht stattgefunden haben. (wenn z.B. die Exception erst beim 3. Satz
auftritt)



Deshalb ja Abbruch bei Fehler. Der Datensatz, bei dem abgebrochen wurde,
wird nicht auf unchanged gesetzt.

Als Lösung sehe ich derzeit nur, die gesamte Logik, die in
OleDbDataAdapter.Update steckt, durch eigenen Code zu ersetzen.



Viel Spass :-)

Er würde
sich nur dadurch unterscheiden, dass AcceptChanges nicht pro verarbeiteter
DataRow aufgerufen wird. Stattdessen würde AcceptChanges erst dann
aufgerufen, wenn vorher _alle_ Sàtze erfolgreich geschrieben werden
konnten. Ist das eine "übliche" Vorgehensweise?



Das kannst du machen. Dazu brauchst du aber nicht deinen eigenen
DataAdapter, sondern nur AcceptChangesDuringUpdate=False setzen und dann nur
für die betroffenen Datensàtze im Erfolgsfall (Commit) AcceptChanges setzen.

Ich meine, auf die Situation, dass ein Update für mehrere Sàtze innerhalb
einer Transaktion erfolgen muss stosse ich ja nicht als erster Mensch
überhaupt. ;-)



Für dein Szenario ist es aber nicht erforderlich, Vorgànge in eine
Transaktion zu kapseln. Wenn du das Update gegen parallele Zugriffe schützen
willst, dann ist eine Transaktion ein möglicher Lösungsweg. Ein weiterer
Grund für Transaktionen wàren Trigger oder Constraints, die Fehler auslösen
können. Wenn du ausschlißelich auf Duplicate im Master-Datensatz durch die
Datenbank prüfen làsst, reicht ein Abbruch, da die nachfolgenden
Aktualisieren der Child-Datensàtze nicht ausgeführt werden.

Viele Grüsse
Peter



Viele Grüsse
Peter

Ähnliche fragen