Ich habe folgendes Problem. Mit einem SqlDataAdapter werden mit der Update Methode Daten aus einem DataSet mit der Datenbank abgeglichen. Nun bekomme ich hin und wieder eine SqlException, dass der Timeout abgelaufen ist. Wie kann ich herausfinden, bei welchem Command genau das Problem auftritt?
Moin,
der StackTrace sollte Dir helfen...
Weiterhin der SQL Profiler...
Enjoy
Christian Arnold
Das Problem trat bei einem internen DELETE auf. Eine Erhöhung von CommandTimeout konnte bereits helfen.
Wie kann ich herausfinden, wieso gerade die DELETE-Anweisung so lange dauert?
Moin,
bitte poste mal Deine Delete-Anweisung...
Enjoy
Christian Arnold
Es gibt keine spezielle DELETE-Anweisung. Ich hole mir ein DataSet aus der Datenbank. Füge entweder Zeilen hinzu oder aktualisiere diese und rufe schließlich die Update-Methode aus.
Also nutzt du einen commandbuilder?
Enjoy
Christian Arnold
Also ich befülle mit "SELECT * FROM tabelle WHERE id = irgendeineZahl" über die Fill-Methode des SqlDataAdapters ein DataSet. Nach einigen Überprüfungen kann es jetzt vorkommen, dass ich eine Zeile lösche und später wieder komplett neu hinzufüge. Dann führe ich die Update-Methode des SqlDataAdapters aus.
Hmm,
also irgendwie musst Du ja dem Adapter einen Delete Befehl geben.
Entweder nutzt Du einen manuellen oder einen CommandBuilder.
Zunächst:
NIEMALS "Select *" verwenden!
Nutzt Du denn nun einen CommandBuilder?
Enjoy
Christian Arnold
Achso, einen CommandBuilder verwende ich nicht. Die DELETE-Anweisung wird dadurch erzeugt, dass ich die Zeile aus dem DataSet herauslösche. Wenn ich nun die Update-Methode des SqlDataAdapters aufrufe, wird hier intern ein DELETE ausgeführt.
Hallo phunkydizco
Verwendest du den SqlDataAdapter Wizard (Configure DataAdapter/Konfiguriere DatenAdapter)?
Wenn ja, dann verwendest du einen CommandBuilder. Ansonsten nicht. (Dann musst du die INSERT, UPDATE, DELETE Commands selbst erstellen.)
Eine möglichkeite wäre (timeout wieder auf den default wert setzen), try/catch um die Update methode. Im catch ein dataSet.dataTable.GetErrors() aufrufen und nachsehen welche Row(s) einen Error verursacht haben. Eventuell steht in der Fehler beschreibung was genaueres drinnen als "timeout occured".
Hab jetzt nochmal genau nachgesehen und ich verwende doch einen CommandBuilder. Den SqlDataAdapter Wizard verwende ich allerdings nicht.
Das mit dem GetErrors ist eine gute Idee. Gibt es eine Möglichkeit die Anweisung bei der der Fehler aufgetreten ist dann nochmal mit einem höheren Timeout zu wiederholen, ohne die Update-Methode mit einer Exception zu verlassen?
Moin,
dann bilde Dir Dein Delete selber. CommandBuilder ist nicht wirklich gut!
Und wie gesagt, zu liebe des Ablaufplans NIEMALS "SELECT *" verwenden!
Bilde Dir selbst Deine Abfragen (INSERT UPDATE DELETE) und vergiss in jedem Fall den CommandBuilder... Vermutlich ist Dein Problem dann vergessen....
Der Builder erzeugt nicht gerade optimale Abfragen / Statements
Enjoy
Christian Arnold
ContinueUpdateOnError beim DatenAdapter auf true stellen und nach dem Update befehl überprüfen ob Fehler aufgetreten sind (GetErrors).
Danach TimeOut erhöhen und versuchen nochmal zu updaten. Aufpassen das es in keiner endlos schleife endet.
Ob es wirklich sinnvoll ist den Update-Methode bei einem Fehler weitermachen zu lassen und dass dann nochmals mit einem höheren Timeout zu wiederholen. Könnten da nicht unterumständen in der Daten doppelte bzw. fehlerhafte Datensätze erzeugt werden.
Die frage ob es sinnvoll ist musst du selbst beantwortet, du hast gefragt ob es geht. Meine antwort ja 🙂
Wenn du eine Exception bei einer INSERT Anweisung bekommst, liegt es daran das es nicht funktioniert hat -> doppelte Datensätze sind also "unmöglich".
Das gleiche bei UPDATE, DELETE.
Wäre es vielleicht möglich die DELETE-Anweisung innerhalb des DataAdapters zu überschreiben?
Ich lösche bestimmte Zeilen anhand von Überprüfungen aus dem DataSet mittels DataRow.Delete() und führe danach die Update()-Methode des DataAdapters aus. Wie könnte ich hier die DELETE-Anweisung überschreiben?
Moin,
also überschrieben wird hier nichts...
Wie ich oben bereits mehrfach erwähnt habe ->
ersetzte den CommandBuilder durch eigene Commands!
Nur so hast Du eine vernünftige Basis.
Enjoy
Christian Arnold
Wie funktioniert das denn mit dem DataAdapter ohne CommandBuilder? Kann ich dann trotzdem im DataSet die Zeilen selber einfügen und löschen und dann die Update()-Methode verwenden?
Insbesondere Punkt: Updating the Database with a DataAdapter and the DataSet
Enjoy
Christian Arnold
Original von phunkydizco
Kann ich dann trotzdem im DataSet die Zeilen selber einfügen und löschen und dann die Update()-Methode verwenden?
Ja.
Der DataAdapter macht folgendes.
Er läuft das DataSet row by row durch und überprüft den RowState. Ist der RowState "Added" wird ein INSERT ausgeführt, "Modified" -> UPDATE, "Deleted" -> DELETE.
Wie diese 3 Befehle erzeugt werden, CommandBuilder oder manuell, ist egal. Sie sollten funktionieren ^^
Ich musste die Commands noch nie selbst schreiben, daher weis ich nicht genau wie die ausehen, bezüglich primary key und parameter.
Genau das ist mein Problem. Wie funktioniert das mit den Parametern, wenn ich mehere Zeilen lösche?
Parameter haben mit löschen mehreren Zeilen nicht zu tun.
Original von phunkydizco
Genau das ist mein Problem. Wie funktioniert das mit den Parametern, wenn ich mehere Zeilen lösche?
Hast Du dir das Dokument überhaubt angesehen?
Als Tip:
Besorge Dir das Buch
Enjoy
Christian Arnold
Habe jetzt die DELETE-Anweisung folgendermaßen überschrieben.
dataAdapter.DeleteCommand = new SqlCommand("DELETE FROM tabelle WHERE Id = @Id");
dataAdapter.DeleteCommand.Parameters.Add("@Id", SqlDbType.Int, 9, "Id");
Wird sich in den nächsten Tagen zeigen, ob sich das TimeOut-Problem damit beheben lässt. Den CommandBuilder werde ich für die anderen Anweisungen wohl erstmal weiter verwenden.
CommandBuilder wirklich NUR wenn absolut einfache Anweisungen auszuführen sind UND Performance absolut KEINE Rolle spielt.
Enjoy
Christian Arnold
Bei meinem CommandBuilder wird nur ein Select/Update anhand einer ID gemacht. Also keine Joins oder sonstiges. Ich denke damit sollte es keine Probleme geben. Werde mir jetzt allerdings die Zeiten der einzelnen Anweisungen mal genauer anschauen und bei Bedarf den CommandBuilder ausbauen.