Parrelitätsverletzung / MS - SQL
-
Task ist eine Klasse die einfach Werte beinhaltet und in einer Datenbank schon
gespeichert wurden. Nun möchte ich diesen "Task" updaten dafür suche ich als
erstes in der Datenbank nach der ID die der Task besitzt. Danach gebe ich die
Row weiter an FillRowWithTaskValues, die diesen Row dann mit den Werten
befüllt. Danach ein einfaches Update doch da entsteht immer folgender Fehler:
Parallelitätsverletzung : Der UpdateCommand hat sich auf 0 der erwarteten 1
Datensätze ausgewirkt. Ich vermute das er diesen Row gar nicht verändert und
das wenn keine Veränderungen bestehen er mir diesen Fehler ausgibt
Hier mal der Code:public void UpdateTask(Task task, DataSet dataSet, SqlDataAdapter adapter, String database) { //Search the max ID int maxIdSort = SearchMaxID(dataSet, database); //Search the Position from the Task int rowPosition = 0; foreach(DataRow row in dataSet.Tables[database].Rows) { if ((int)row["ID"] != task.Id) rowPosition++; else break; } //Fill the row with the datas from the Task FillRowWithTaskValues(task, maxIdSort, dataSet.Tables[database].Rows[rowPosition]); SqlCommandBuilder cmb = new SqlCommandBuilder(adapter); //Update database adapter.Update(dataSet.Tables[database]); }
private static void FillRowWithTaskValues(Task task, int maxIdSort, DataRow row) { row.BeginEdit(); row["User"] = task.User; row["Done"] = task.Done; row["Text"] = task.Text; row["TitleText"] = task.TitleText; row["Header"] = task.Header; row["CreateDate"] = task.CreateDate; row["SizeWidth"] = task.Size.Width; row["SizeHeight"] = task.Size.Height; row["X"] = task.Location.X; row["Y"] = task.Location.Y; row["FontName"] = task.Font.Name; row["Bold"] = task.Font.Bold; row["Italic"] = task.Font.Italic; row["FontSize"] = task.Font.Size; row["TitleFontName"] = task.TitleFont.Name; row["TitleBold"] = task.TitleFont.Bold; row["TitleItalic"] = task.TitleFont.Italic; row["TitleFontSize"] = task.TitleFont.Size; row["TaskColor"] = task.TaskColor.ToArgb(); row["TitleTextColor"] = task.TitleTextColor.ToArgb(); row["TitleColor"] = task.TitleColor.ToArgb(); row["TextBackgroundColor"] = task.TextBackgroundColor.ToArgb(); row["TextColor"] = task.TextColor.ToArgb(); row["BorderSize"] = task.BorderSize; row["TitleDistance"] = task.TitleDistance; row["ID_Sort"] = maxIdSort; row["Edit"] = task.Edit; row.EndEdit(); }
Wisst ihr vielleicht woran es liegt? Ich hoff der Code ist leserlich.
Danke
-
Problem gefunden:
cmb.ConflictOption = ConflictOption.OverwriteChanges;
musste ich noch mit einfügen. Fehler behoben
Aber mich würde trodzdem gern interessieren wieso ich eine Parallelitätsverletzung verursacht habe.
Danke
-
Frager schrieb:
Fehler behoben
Guter Scherz, von wegen!
Das Problem ist, dass die originalen Datensätze Deiner DataTable in der Datenbank geändert haben. Sprich: Irgendwer oder irgendwas hat eine Änderung an dem Datensatz vorgenommen den Du aktualisieren willst - das ist Parallelitätsverletzung. Mit den ConflictOptions ignorierst Du das Problem nur und überschreibst die Änderungen in der DB. Wenn Dein Programm ein Mehrbenutzersystem ist dann Prost Mahlzeit, wenn Du das so einsetzen willst. Wenn Du SQL 2005 einsetzt, dann schaue Dir mal die SQL-Notifications an, aber Achtung, das ist eher was für Serverprogramme!
-
SeboStone schrieb:
Frager schrieb:
Fehler behoben
Guter Scherz, von wegen!
Das Problem ist, dass die originalen Datensätze Deiner DataTable in der Datenbank geändert haben. Sprich: Irgendwer oder irgendwas hat eine Änderung an dem Datensatz vorgenommen den Du aktualisieren willst - das ist Parallelitätsverletzung. Mit den ConflictOptions ignorierst Du das Problem nur und überschreibst die Änderungen in der DB. Wenn Dein Programm ein Mehrbenutzersystem ist dann Prost Mahlzeit, wenn Du das so einsetzen willst. Wenn Du SQL 2005 einsetzt, dann schaue Dir mal die SQL-Notifications an, aber Achtung, das ist eher was für Serverprogramme!
oh
das heißt das seit dem letzten Aktualisierung meines DataTables im Programm sich der Originale Datensatz in der Datenbank sich bereits geändert hat?
Wenn ja welche folgen könnten es sich da nach sich ziehen wenn ich diesen Fehler ignoriere?Danke
-
Ja genau!
Wie bereits geschrieben, Du überschreibst die in der Datenbank gemachten Änderungen, die sind dann einfach mal weg.
-
Ok alles klar ich werde einfach das DataTable vor dem TaskUpdate die DataTable aktualisiere. Müsste so behoben seien, oder? Mit Notifiy möchte ich mich erstmal noch nicht auseinandersetzen.
Danke für deine Hilfe
-
Das lässt sich so pauschal nicht sagen. Zwischen dem Neubefüllen Deines DataSets und Deines tatsächlichen Updates vergeht ebenfalls Zeit in der jemand anderes Änderungen durchführen kann. Nur wenn Du einen Lock auf die Datensätze legst (was ein super performancekiller sein kann) kannst Du sicher sein, dass sie nicht geändert werden bevor Du Deine Änderungen eingespielt hast.
-
Hm locks sind Riskant in meinen Programm da es schnell sein muss, und desweiteren wegen den Deadlocks. Ich hab es über diesen weg gelöst das ich direkt
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION; UPDATE EDIT = TRUE WHERE ID = 0 COMMIT TRANSACTION;
An die Datenbank gebe und immer überprüfe ob er bearbeitet wird.
Habe es auch gerade ausprobiert mit 2 rechnern die fast gleichzeitig einen Task Updaten. Der eine PC wurde geblockt der andere hatte zugriff. Ich hoff das, dass eine saubere lösung war.
wenn nicht bitte bescheid sagen.
Danke dir Sebo
-
Das Problem besteht immer noch. Da Du nur ein Update-Kommando ausführst ist die Transaktion überflüssig, bzw. bringt nix ausser Zeitverlust.
Um eine Parallelitätsverletzung noch mal genau zu skizzieren:
time | task 1 | task 2
----------------------------
1 | lesen | --
2 | -- | lesen
3 | schreiben | --
4 | -- | schreibenDu versuchst zum Zeitpunkt 4 zu schreiben, dabei ist es völlig egal ob Du den Zeitpunkt 4 in eine Transaktion packst oder nicht, bringt nix. Wenn Du's mit Transaktionen lösen willst, dann packe für task 2 den Zeitpunkt 2 + 4 in eine Transaktion, für task 1 den Zeitpunkt 1 + 3 in eine Transaktion.