![]() |
Exception richtig behandeln
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo zusammen,
ich habe mal eine Frage zur Behandlung von Exceptions. Ich lese Daten aus einer Textdatei in eine Datenbank ein. Wenn jetzt z.B. Das eingelesen Datum kein gültigen Datumswert hat, wird natürlich eine Meldung beim eintragen in die Datenbank erzeugt, die mir sagt, '' ist kein gültiges Datum. (siehe Anhang). Wie kann ich jetzt in mein Commit eine sauber Exeptionbehandlung einbauen, die diese Datensätze einfach nicht übernimmt. Probiert habe ich das ganz so, funktioniert aber leider nicht.
Delphi-Quellcode:
Danke schon mal und Gruß
VST.BeginUpdate;
for i := 0 to High(Parser.EntriesMB256) do begin Daten := TOMBSerie.Create; with Daten do begin DM_PS.Qry_InsertMB256.Close; DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr; DM_PS.QryImportMB256.ParamByName('Datum').AsDate := StrToDate(Parser.EntriesMB256[i].Datum); DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit); DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis; DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer; DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich; DM_PS.QryImportMB256.ExecSQL; try DM_PS.ConPSSecur.Commit; DM_PS.QrySelectMaxIDMB256.Open; except on e : Exception Do begin ShowMessage(e.Message); end; end; Daten.ID := DM_PS.QrySelectMaxIDMB256.FieldByName('ID').AsInteger; Daten.LfdNr := Parser.EntriesMB256[i].LfdNr; Daten.Datum := Parser.EntriesMB256[i].Datum; Daten.Uhrzeit := Parser.EntriesMB256[i].Uhrzeit; Daten.Ereignis := Parser.EntriesMB256[i].Ereignis; Daten.Teilnehmer := Parser.EntriesMB256[i].Teilnehmer; Daten.Bereich := Parser.EntriesMB256[i].Bereich; end; VST.AddChild(nil, Daten); DM_PS.QrySelectMaxIDMB256.Close; Label6.Caption := IntToStr(StrToInt(Label6.Caption)+1); ProgBarDatei.Position := ID; Inc(ID); VST.ScrollIntoView(VST.GetLast, true); VST.EndUpdate; DM_PS.QrySelectMaxIDMB256.Close; end; end; Jens |
Re: Exception richtig behandeln
Der Fehler tritt ja beim StrToDate auf, das jedoch fängst du gar nicht ab. Du solltest lieber mit TryStrToDate usw. arbeiten, dann kannst du bei nicht erfolgreicher Umwandlung auch die Eintragung gar nicht erst versuchen.
|
Re: Exception richtig behandeln
Grundsätzlich sollten solche Funktionen nur mit garantiert gültigen Parametern aufgerufen werden. Das bedeutet für Dich, das du eine Sicherheitsschicht um diese eigentliche Funktion bauen musst. Diese Sicherheitsschicht nimmt die Parameter entgegen, prüft sie und wirft ggf eine Exception. Erst bei Korrektheit wird die Funktion aufgerufen. Diese kann dann wieder Fehler verursachen, die dann aber isoliert und 'in Ruhe' betrachtet werden können.
|
Re: Exception richtig behandeln
Ich würde an deiner Stelle eine StringListe erzeugen oder der Funktion von Aussen übergeben um darin alle Fehlermeldungen zu sammeln.
Delphi-Quellcode:
Die Fehlerliste wird dem Benutzer am Ende präsentiert ohne dass der Benutzer jeden Fehler einzeln quittieren muss.
except
on e : Exception Do begin fehlerliste.Add(Format('Entry %d: %s|%s',[i, e.Classname, e.Message])); end; end; (ein riesen Vorteil, wenn es mal 50 oder mehr Fehler werden sollten) Ausserdem wird auch die Entry-Nummer festgehalten; das ist wichtig, wenn man die Ursache der Fehler herausfinden möchte. |
Re: Exception richtig behandeln
Hallo,
also irgendwie zue ich mir mit Exceptionbehandlungen noch sehr schwer. Ich habe die jetzt geändert, aber der Fehler ist immer noch da. Hier mal mein neuer Code.
Delphi-Quellcode:
Vieleicht kann mir ja mal jemand sagen, wo der Fehler liegt, und mal erklären, wie ich am besten an eine solch Try/Except Sache dran gehe.
try
DM_PS.Qry_InsertMB256.Close; DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr; DM_PS.QryImportMB256.ParamByName('Datum').AsDate := StrToDate(Parser.EntriesMB256[i].Datum); DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit); DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis; DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer; DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich; DM_PS.QryImportMB256.ExecSQL; DM_PS.ConPSSecur.Commit; except on e : Exception Do begin Fehlerliste.Add(Format('Entry %d: %s|%s',[i, e.Classname, e.Message])); end; end; Danke schon aml Gruß Jens |
Re: Exception richtig behandeln
Liste der Anhänge anzeigen (Anzahl: 1)
Was heißt der Fehler ist noch da? Dass Delphi den anzeigt, wenn du das Programm aus Delphi startest? Das passiert immer, wenn der Debugger aktiv ist.
Um das zu verhindern, kannst du (wenn der Fehler angezeigt wird) dessen Anzeige einfach mit der CheckBox deaktivieren. (Siehe Anhang) Oder einfach das Programm nicht aus Delphi sondern separat starten (Menü Start --> Ohne Debugger ausführen). // EDIT: Auf TryStrToDate stattdessen habe ich ja schon hingewiesen, das wäre noch besser... |
Re: Exception richtig behandeln
Liste der Anhänge anzeigen (Anzahl: 3)
Das ist mir schon klar.
Der Fehler, kommt aber auch, wenn ich ohne Debugger ausführe, da ja ein Fehler vorhanden ist. Ich muss ja realisieren, wodurch der Fehler kommt, um diesen dann auszuschliessen. Nur wenn ich im Debugger auf Anhalten klicke, um an die Stelle im Code zu gelangen, wo der Fehler passiert, lande ich irgendwo im Quellcode der ZEOS Kompo und wieß jetzt nicht, wie ich anfangen kann diesen Abzufangen. Hier nochmal die Fehlermeldungen und der Code in dem ich bei Anhalten lande.
Delphi-Quellcode:
procedure CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver;
StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther; SQL: string = ''); var Msg: array[0..1024] of Char; PStatusVector: PISC_STATUS; ErrorMessage, ErrorSqlMessage: string; ErrorCode: LongInt; begin if (StatusVector[0] = 1) and (StatusVector[1] > 0) then begin ErrorMessage:=''; PStatusVector := @StatusVector; while PlainDriver.isc_interprete(Msg, @PStatusVector) > 0 do ErrorMessage := ErrorMessage + ' ' + StrPas(Msg); ErrorCode := PlainDriver.isc_sqlcode(@StatusVector); PlainDriver.isc_sql_interprete(ErrorCode, Msg, 1024); ErrorSqlMessage := StrPas(Msg); {$IFDEF INTERBASE_EXTENDED_MESSAGES} if SQL <> '' then SQL := Format(' The SQL: %s; ', [SQL]); {$ENDIF} if ErrorMessage <> '' then begin DriverManager.LogError(LoggingCategory, PlainDriver.GetProtocol, ErrorMessage, ErrorCode, ErrorSqlMessage + SQL); {$IFDEF INTERBASE_EXTENDED_MESSAGES} raise EZSQLException.CreateWithCode(ErrorCode, Format('SQL Error: %s. Error Code: %d. %s', [ErrorMessage, ErrorCode, ErrorSqlMessage]) + SQL); Zitat:
MFG jens |
Re: Exception richtig behandeln
Hallo Jens,
Exception 2: Erklärt sich von selbst. irgendwo, wo ein Date Wert sein sollte ist nix. Exception 1: Kommt ganz gern, wenn die Länge des Strings die Feldgröße überschreitet. die Zugriffsverletztung :gruebel: |
Re: Exception richtig behandeln
Zitat:
Delphi-Quellcode:
// EDIT:
var
DateValue: TDate; begin ... if not TryStrToDate(DeinString, DateValue) then begin ShowMessage('Fehler bei Umwandlung von ' + DeinString + ' in einen Datumswert'); Exit; // abbrechen oder so end; ... // Wenn alles erfolgreich war, dann die Werte benutzen: DateValue ... Ja, ich weiß, Exit ist nicht unbedingt ein schöner Programmfluss, kann man natürlich auch umgekehrt formulieren. Zu den SQL-Fehlern sage ich mangels Erfahrung lieber nix. :mrgreen: |
Re: Exception richtig behandeln
Zitat:
|
Re: Exception richtig behandeln
wenn ich dich richtig verstanden habe möchtest du nur die Datensätze eintagen, die kpl. und gültige Werte haben. Alles andere soll über die Exception abgefangen werden.
sinngemäß, da du mit Zeos arbeitest.
Delphi-Quellcode:
damit hat jeder Datensatz eine eigene Transaktion bekommen. Wenn die Werte ungültig sind läuft das ganze in´s except und die Transaktion wird zurückgenommen. Vieleicht solltest du aber schon beim Parser auf ungültige Werte prüfen und entsprechend reagieren. Die Feldgrößen würde ich größer wählen falls du nicht weist, wie die Strings ausfallen.
for ... do
begin StartTransaction try SQL.Text:= .... Parameter .... ExecSQL Commit; except Rollback; ..... end end :hi: :roll: wie immer zu langsam |
Re: Exception richtig behandeln
Hallo und danke an alle,
habe das ganze jetzt mal nach Euren Vorschlägen umgebaut und es funktioniert. Wäre jetzt nur die Frage, weil ich wie schon gesagt, mit den Exeptions nicht so sicher bin, ob das Soweit OK ist. Hier mal der funktionierende Code...
Delphi-Quellcode:
:gruebel:
procedure TImportForm.DisplayResult(Parser: TMySimpleBaseParser);
var i: Integer; ID : Integer; Daten : TOMBSerie; Fehlerliste : TStringlist; OutDatum : TDateTime; begin ID := 1; ProgBarDatei.Max := High(Parser.EntriesMB256); VST.BeginUpdate; for i := 0 to High(Parser.EntriesMB256) do begin Daten := TOMBSerie.Create; with Daten do begin try if TryStrToDate(Parser.EntriesMB256[i].Datum,OutDatum) = true then begin DM_PS.Qry_InsertMB256.Close; DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr; DM_PS.QryImportMB256.ParamByName('Datum').AsDate := OutDatum; DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit); DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis; DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer; DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich; DM_PS.QryImportMB256.ExecSQL; DM_PS.ConPSSecur.Commit; end else begin FehlerMemo.Lines.Add('Fehler in Datensatz '+IntToStr(Parser.EntriesMB256[i].LfdNr)); FehlerMemo.Lines.Add('In Datei'); FehlerMemo.Lines.Add(Label1.Caption); FehlerMemo.Lines.Add(''); Label9.Caption := IntToStr(StrToInt(Label9.Caption)+1); end; except DM_PS.ConPSSecur.Rollback; end; DM_PS.QrySelectMaxIDMB256.Open; Daten.ID := DM_PS.QrySelectMaxIDMB256.FieldByName('ID').AsInteger; Daten.LfdNr := Parser.EntriesMB256[i].LfdNr; Daten.Datum := Parser.EntriesMB256[i].Datum; Daten.Uhrzeit := Parser.EntriesMB256[i].Uhrzeit; Daten.Ereignis := Parser.EntriesMB256[i].Ereignis; Daten.Teilnehmer := Parser.EntriesMB256[i].Teilnehmer; Daten.Bereich := Parser.EntriesMB256[i].Bereich; end; VST.AddChild(nil, Daten); DM_PS.QrySelectMaxIDMB256.Close; Label6.Caption := IntToStr(StrToInt(Label6.Caption)+1); ProgBarDatei.Position := ID; Inc(ID); end; VST.ScrollIntoView(VST.GetLast, true); VST.EndUpdate; DM_PS.QrySelectMaxIDMB256.Close; end; Danke nochmal Gruß Jens |
Re: Exception richtig behandeln
Ich würde es andersherum schreiben:
Delphi-Quellcode:
Wobei ich vielleicht nicht jeden Datensatz committen würde, sondern in Blöcken von z.B. 50. Und müsste anschließend nicht eine neue Transaktion gestartet werden?
...
with Daten do begin if TryStrToDate(Parser.EntriesMB256[i].Datum,OutDatum){ = true} then try DM_PS.Qry_InsertMB256.Close; DM_PS.QryImportMB256.ParamByName('LfdNr').AsInteger := Parser.EntriesMB256[i].LfdNr; DM_PS.QryImportMB256.ParamByName('Datum').AsDate := OutDatum; DM_PS.QryImportMB256.ParamByName('Uhrzeit').AsTime := StrToTime(Parser.EntriesMB256[i].Uhrzeit); DM_PS.QryImportMB256.ParamByName('Ereignis').AsString := Parser.EntriesMB256[i].Ereignis; DM_PS.QryImportMB256.ParamByName('Teilnehmer').AsString := Parser.EntriesMB256[i].Teilnehmer; DM_PS.QryImportMB256.ParamByName('Bereich').AsString := Parser.EntriesMB256[i].Bereich; DM_PS.QryImportMB256.ExecSQL; DM_PS.ConPSSecur.Commit; except DM_PS.ConPSSecur.Rollback; end else begin FehlerMemo.Lines.Add('Fehler in Datensatz '+IntToStr(Parser.EntriesMB256[i].LfdNr)); FehlerMemo.Lines.Add('In Datei'); FehlerMemo.Lines.Add(Label1.Caption); FehlerMemo.Lines.Add(''); Label9.Caption := IntToStr(StrToInt(Label9.Caption)+1); end; ... |
Re: Exception richtig behandeln
Hallo Jens,
ich vermisse auch den Start der Transaktion. Zeos kann nur eine. Wenn AutoCommit deiner Connection auf True steht wird automatisch mit ExecSQl ein "Commit" ausgeführt. (Wie wir wissen, nur ein SoftCommit) Somit greift dein Commit eh nicht. Wie es mit dem Rollback aussieht hab ich noch nicht getestet, da ich immer eine separate Transaktion aufmache. (StartTransaktion...Commit...Rollback) :hi: |
Re: Exception richtig behandeln
Also, das was DeddyH gezeígt hat, kann ich umsetzten und funktioniert auch. Allerdings das von
Zitat:
Kannst Du mir das mal erklären. Gruß Jens |
Re: Exception richtig behandeln
Zeos hat standardmäßig eine Transaktion. Das heißt mit jedem ExecSQL (bei AutoCommit = True) wird diese Transaktion intern Commited und eine neue geöffnet. Dein Commit ist unnötig.
wenn du jetzt z.B. mehrere SQL Anweisungen als "Block" abarbeiten willst machst du eine neue Transaktion auf. StartTransaktion try ExecSQL1 ExecSQL2 ExecSQL3 Commit except Rollback end tritt in einer der SQL Anweisungen ein Fehler auf werden alle SQL Anweisungen zurückgenommen, da sie in einer Transaktion laufen. Unterschied verstanden ? :hi: PS: ich mache mir standardmäßig eine neue auf. Auch mit nur einer SQL Anweisung. Es könnte ja noch eine dazukommen und du kannst genau festlegen wann Commited wird. |
Re: Exception richtig behandeln
Ich habe in meiner Connection AutoCommit auf false sitzen. Deshalb führe ich das Commit aus.
Dachte bislang das das OK so ist. Sollte man das anders machen??? :gruebel: Gruß Jens |
Re: Exception richtig behandeln
wenn AutoCommit = False dann ist dein Commit ok und nötig. Dann ist das so in Ordnung. Wenn du aber z.B. in mehrere Tabellen schreiben möchtest und die Daten immer komplett sein müssen solltest du eine neue Transaktion öffnen und die SQL Anweisungen damit "zusammenfassen".
hoffe trotzdem dir geholfen zu haben :hi: |
Re: Exception richtig behandeln
Ja, aufjedenfall.
Ich bin echt immer und über jede Hilfe froh. Es ist als Hobbyprogrammierer nicht immer einfach, wenn man die Sachen alle erlesen muss. Das Thema Programmieren, ist ja schließlich kein kleines. Also nochmal Danke. Gruß Jens |
Re: Exception richtig behandeln
Geht mir nicht anders, sich in etwas einzuarbeiten und auszuprobieren ist das zeitaufwändigste überhaupt.
einen schönen Sonntag noch :hi: |
Re: Exception richtig behandeln
Nur so als Hinweis: alle StrToXXX Konverter Funktionen können die selbe Exception werfen wie bei StrToDate. Dafür gibts immer die passende TryStrToXXX Funktion. :warn:
|
Re: Exception richtig behandeln
Zitat:
Danke für die Info. Ich denke, das ich das in alle meine Funktionen noch integrieren werde. Gruß Jens |
Re: Exception richtig behandeln
Hallo,
ich bin immer noch dabei meine Exceptionbehandlungen zu ergänzen. Ist es OK, wenn ich am Anfang meiner Funktion, in der verschiedene Fehler auftreten können, Umwandlungen von Zeit in String oder String in Integer etc. in einem großen gemeinsamen
Delphi-Quellcode:
Block packe. Und wäre es OK, wenn der
try
except
Delphi-Quellcode:
Teil dann leer ist. Wenn ich wie unten das so machen würde, dann wäre ja im except Block keine Anweisung notwendig, da ja der obere
except
Delphi-Quellcode:
Block komplett abgebrochen wird. Also denke ich brauche ich auch kein Rollback und so.
try
Delphi-Quellcode:
Danke schon mal Gruss
procedure TForm1.TreeViewResultMB100(ParserTreeViewMB100: TMyBaseParser);
var Daten : TOMBSerie; begin try QryMB100.Close; QryMB100.SQL.Text := 'INSERT INTO MB100'+ '(LFDNR, DATUM, UHRZEIT, EREIGNIS, TEILNEHMER, BEREICH)'+ 'VALUES(:LfdNr,:Datum,:Uhrzeit,:Ereignis,:Teilnehmer,:Bereich)'; QryMB100.ParamByName('Lfdnr').AsInteger := ParserTreeViewMB100.EntriesMB100[0].LfdNr; QryMB100.ParamByName('Datum').AsDate := StrToDate(ParserTreeViewMB100.EntriesMB100[0].Datum); QryMB100.ParamByName('Uhrzeit').AsTime := StrToTime(ParserTreeViewMB100.EntriesMB100[0].Uhrzeit); QryMB100.ParamByName('Ereignis').AsString := ParserTreeViewMB100.EntriesMB100[0].Ereignis; QryMB100.ParamByName('Teilnehmer').AsString := ParserTreeViewMB100.EntriesMB100[0].Teilnehmer; QryMB100.ParamByName('Bereich').AsString := ParserTreeViewMB100.EntriesMB100[0].Bereich; QryMB100.ExecSQL; ConSecurdat.Commit; QryMB100.Close; QryMB100.SQL.Text := 'Select Max(ID) As ID From MB100'; QryMB100.Open; VST.BeginUpdate; Daten := TOMBSerie.Create; with Daten do begin Daten.ID := QryMB100.FieldByName('ID').AsInteger; Daten.LfdNr := ParserTreeViewMB100.EntriesMB100[0].LfdNr; Daten.Datum := ParserTreeViewMB100.EntriesMB100[0].Datum; Daten.Uhrzeit := ParserTreeViewMB100.EntriesMB100[0].Uhrzeit; Daten.Ereignis := ParserTreeViewMB100.EntriesMB100[0].Ereignis; Daten.Teilnehmer := ParserTreeViewMB100.EntriesMB100[0].Teilnehmer; Daten.Bereich := ParserTreeViewMB100.EntriesMB100[0].Bereich; end; VST.AddChild(nil, Daten); if VST.RootNodeCount >= 4001 then begin VST.DeleteNode(VST.GetFirst); end; VST.EndUpdate; VST.ScrollIntoView(VST.GetLast, true); QryMB100.Close; DataMB256plus := ''; except end; end; Jens |
Re: Exception richtig behandeln
Ein leerer except-Block sieht aber komisch aus. Wie wäre es, wenn du den Benutzer darüber informierst, dass da etwas schief gegangen ist?
Das ist bei dir ein wenig so als ob bei einem Auto der Reifen überhitzt, der Bordcomputer das feststellt, aber trotzdem nur die Lüftungszufuhr verschließt, damit im Auto der Rauch nicht stört... (bis der Reifen platzt) |
Re: Exception richtig behandeln
Das Problem, ist eigendlich das mich der Teil normalerweise nicht interesiert.
Sollte in dem
Delphi-Quellcode:
Block ein Exception auftreten, entsteht diese zu 99,9% bei einem RESET der Hardware, da der dann folgende 1.Datensatz unterumständen nicht Ordnungsgemäß ist. Das soll heißen, das bei 100000 Datensätzen, das eventuell das bei einem mal passieren kann.
try
Gut wenn eine unerwartet Exception auftritt, wäre es eventuell Sinnvoll. Dann müsste ich dies vieleicht in ein Fehlerprotokoll oder so schreiben. Ist es den ansonsten OK, den
Delphi-Quellcode:
Block über die gesamte Funktion zu legen.
try except
MFG Jens |
Re: Exception richtig behandeln
Ja, gut, wenn das normal ist, dass die Daten nicht immer korrekt analysiert werden können, dann braucht man das nicht anzeigen. Allerdings wäre es dann umso sinnvoller wie bereits angesprochen zuerst zu prüfen, ob die Daten valide sind bevor diese einfach eingetragen werden bzw. das versucht wird. Die Try... Funktionen wurden ja angesprochen und ich hatte gedacht du wolltest das auch entsprechend umbauen?
Zitat:
|
Re: Exception richtig behandeln
Ja, das stimmt wohl. Ich werde das jetzt mal umschreiben und dann mal hier einstellen.
Danke erstmal Gruß Jens |
Re: Exception richtig behandeln
Hallo mal wieder zusammen, :chat:
ich will mal wieder ein altes Thema von mir aufleben lassen. Ich habe vor kurzer Zeit ein wenig an meinen Exceptionbehandlungen gearbeitet. Ich habe mich nochmal in das Thema eingelesen und einen Teil von meinem Programm angefangen auf meine Kenntnisse anzupassen. Da ich aber jetzt nicht unnötig arbeiten will und gerne mal Eure Meinung hören würde, wäre es schön wenn ihr mal kurz zu dem folgenden Code Eure Meinung sagen könnte. :idea:
Delphi-Quellcode:
Danke schon mal und Gruß
{HTML in Datei speichern}
function THTMLExportForm.SaveHTML(HTMLFile : TStringlist):string; begin if SaveDialog1.Execute then HTMLFile.SaveToFile(SaveDialog1.FileName); Result := SaveDialog1.FileName; end; {HTML-Datei für MB-Serie erstellen} procedure THTMLExportForm.HTMLErzeugenMBSerie; Var slHTML : TStringList; i : integer; mrResult: Integer; FileName : String; begin try //start try Block mit finally für HTML.Free try //start try Block Erstellung HTML slHTML := TStringList.Create; slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'); slHTML.Add('<html>'); slHTML.Add('<head>'); slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"'); slHTML.Add('<Style type="text/css"></style>'); slHTML.Add('<title>Protokolldatei</title>'); slHTML.Add('</head>'); slHTML.Add('<body>'); slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >'); slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>'); slHTML.Add('<h1 style="color:#000080;">Objekt: ' +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>'); slHTML.Add('<table border="0" style="border-collapse:separate;"'+ 'width="100%" style="'+ 'border-left:5px solid #000080;border-right:5px solid #000080;'+ 'border-top:5px solid #000080;border-bottom:5px solid #000080;>'); slHTML.Add('<tr>'); slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>'); slHTML.Add('<th align="left">ID</th>'); slHTML.Add('<th align="left">LfdNr</th>'); slHTML.Add('<th align="left">Datum</th>'); slHTML.Add('<th align="left">Uhrzeit</th>'); slHTML.Add('<th align="left">Ereignis</th>'); slHTML.Add('<th align="left">Teilnehmer</th>'); slHTML.Add('<th align="left">Bereich</th>'); slHTML.Add('<tr>'); for i := 0 to QryHTML.RecordCount -1 do begin slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Ereignis').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Bereich').AsString); slHTML.Add('</td>'); slHTML.Add('</tr>'); QryHTML.Next; end; slHTML.Add('</table>'); slHTML.Add('</body>'); slHTML.Add('</html>'); except //Ende try Block Exceptionbehandlung Erstellung HTML ShowMessage('HTML Dokument konnte nicht erstellt werden'); end; //Ende try Block end Erstellen HTML try //Start try Block Speichern FileName := SaveHTML(slHTML); except //Ende try Block Exceptionbehandlung Speichern ShowMessage('Datei konnte nicht gespeichert werden'); end; //Ende try Block end Speichern try //Start try Block Datei Öffnen if AnzeigenCheckBox.Checked then ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal); except //Ende try Block Exceptionbehandlung Öffnen ShowMessage('Datei konnte nicht geöffnet werden'); end; //Ende try Block end Öffnen try //Start try Block Datei EMail versenden if VersendenCheckBox.Checked then SendMail(FileName); except //Ende try Block Exceptionbehandlung EMail versenden ShowMessage('Datei konnte nicht als E-Mail versendet werden'); end; //Ende try Block end EMail versenden try //Start try Block Datei Drucken if DruckenCheckBox.Checked then ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE); except //Ende try Block Exceptionbehandlung Drucken ShowMessage('Datei konnte nicht gedruckt werden'); end; //Ende try Block end Drucken finally //Ende try Block TStringlist über finally wieder freigeben slHTML.Free; end; //Ende try Block finally end; Jens |
Re: Exception richtig behandeln
Folgender Code hat gleich drei Fehler:
Delphi-Quellcode:
1.) Fehler
try //Start try Block Datei EMail versenden
if VersendenCheckBox.Checked then SendMail(FileName); except //Ende try Block Exceptionbehandlung EMail versenden ShowMessage('Datei konnte nicht als E-Mail versendet werden'); end; //Ende try Block end EMail versenden die ursprüngliche Exception-Meldung geht verloren. Die Funktion SendMail() kann (wenn sie was taugt) wertvolle Hinweise gegeben, WESHALB die EMail nicht gesendet werden konnte. Es wäre doch wirklich dumm, diese Information einfach so wegzuwerfen. 2.) Fehler Verwendung von ShowMessage. Wenn obiger Try..except Block innerhalb einer Schleife aufgerufen wird und es zum Fehler kommt, dann viel Spass beim Wegklicken der Fehlermeldungen. Oftmals bleibt nichts anderes übrig, als das Programm mit dem Taskmanager abzuschiesen. 3.) Fehler Deine Kommentare sind nichts anderes als visuelles Störfeuer! Es ist sinnlos und kontraproduktiv das Offensichtliche zu kommentieren. Viel besser wäre:
Delphi-Quellcode:
try
if VersendenCheckBox.Checked then SendMail(FileName); except on E:Exception do begin Exception.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+ Exception.Message; raise; end; end; |
Re: Exception richtig behandeln
Zitat:
Delphi-Quellcode:
Kann ich dann eigendlcih auch einfach einen
{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie; Var slHTML : TStringList; i : integer; mrResult: Integer; FileName : String; begin try try slHTML := TStringList.Create; slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'); slHTML.Add('<html>'); slHTML.Add('<head>'); slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"'); slHTML.Add('<Style type="text/css"></style>'); slHTML.Add('<title>Protokolldatei</title>'); slHTML.Add('</head>'); slHTML.Add('<body>'); slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >'); slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>'); slHTML.Add('<h1 style="color:#000080;">Objekt: ' +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>'); slHTML.Add('<table border="0" style="border-collapse:separate;"'+ 'width="100%" style="'+ 'border-left:5px solid #000080;border-right:5px solid #000080;'+ 'border-top:5px solid #000080;border-bottom:5px solid #000080;>'); slHTML.Add('<tr>'); slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>'); slHTML.Add('<th align="left">ID</th>'); slHTML.Add('<th align="left">LfdNr</th>'); slHTML.Add('<th align="left">Datum</th>'); slHTML.Add('<th align="left">Uhrzeit</th>'); slHTML.Add('<th align="left">Ereignis</th>'); slHTML.Add('<th align="left">Teilnehmer</th>'); slHTML.Add('<th align="left">Bereich</th>'); slHTML.Add('<tr>'); for i := 0 to QryHTML.RecordCount -1 do begin slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Ereignis').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Bereich').AsString); slHTML.Add('</td>'); slHTML.Add('</tr>'); QryHTML.Next; end; slHTML.Add('</table>'); slHTML.Add('</body>'); slHTML.Add('</html>'); except on e : Exception do begin TForm1.Servicememo.Lines.Add(e.Message); raise; end; end; try FileName := SaveHTML(slHTML); except on e : Exception do begin e.Message := 'Datei konnte nicht gespeichert werden'#13#10+e.Message; raise; end; end; try if AnzeigenCheckBox.Checked then ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal); except on e : Exception do begin e.Message := 'Datei konnte nicht geöffnet werden'#13#10+e.Message; raise; end; end; try if VersendenCheckBox.Checked then SendMail(FileName); except on e : Exception do begin e.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+e.Message; raise; end; end; try if DruckenCheckBox.Checked then ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE); except on e : Exception do begin e.Message := 'Datei konnte nicht gedruckt werden'#13#10+e.Message; raise; end; end; finally slHTML.Free; end; end; {HTML in Datei speichern} function THTMLExportForm.SaveHTML(HTMLFile : TStringlist):string; begin if SaveDialog1.Execute then HTMLFile.SaveToFile(SaveDialog1.FileName); Result := SaveDialog1.FileName; end; {HTML-Datei als E-Mail versenden} procedure THTMLExportForm.SendMail(HTMLFileName : String); var Attachment : TStringList; i : integer; begin try QryVorgabe.Close; QryVorgabe.SQL.Text := 'SELECT * FROM VORGABE'; QryVorgabe.Open; except on e : Exception do begin e.Message := 'Datenbank konnte nicht geöffnet werden'#13#10+e.Message; raise; end; end; try Attachment := TStringList.Create; Attachment.Add(HTMLFileName); Attachment.Add('.\Kopf1.bmp'); with mesgMessage do begin Clear; From.Text := QryVorgabe.FieldByName('EIGENE_E_MAIL').AsString; Recipients.Add.Text := AnEMailEdit.Text; Subject := BetreffEdit.Text; Body.Assign(EMailMemo.Lines); if FileExists(HTMLFileName) then begin if assigned(Attachment) then for i := 0 to Attachment.Count - 1 do TIdAttachmentFile.Create(MessageParts, Attachment.Strings[i]); end end; with smtpSendMail do begin Username := QryVorgabe.FieldByName('BENUTZERNAME_E_MAIL').AsString; Password := QryVorgabe.FieldByName('PASSWORT_E_MAIL').AsString; Host := QryVorgabe.FieldByName('SMTP_SERVER').AsString; Connect; try Send(mesgMessage); finally Disconnect; end; end; showmessage('Mail wurde erfolgreich an folgende Adressen versendet.'+sLineBreak+sLineBreak+ 'An: '+AnEMailEdit.Text); finally Attachment.Free; end; QryVorgabe.Close; end;
Delphi-Quellcode:
Block für die gesamten Anweisung nehmen und das ganze dann so machen...
try..except
Delphi-Quellcode:
Das müsste doch so auch gehen...
{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie; Var slHTML : TStringList; i : integer; mrResult: Integer; FileName : String; begin try try slHTML := TStringList.Create; slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'); slHTML.Add('<html>'); .... .... if VersendenCheckBox.Checked then SendMail(FileName); .... .... if DruckenCheckBox.Checked then ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE); except on e : Exception do begin Memo1.Lines.Add := 'Fehler beim erstellen der Datei'; Memo1.Lines.Add := 'Fehler aufgetreten: '+e.Message; if FehlerCheckBox.Cheched then raise; //Wenn CheckBox Fehleranzeigen aktiv, wird der Fehler angezeigt, ansonsten nur Eintrag im Memo end; end; finally slHTML.Free; end; end; Gruß Jens |
Re: Exception richtig behandeln
Zerleg deine Methode HTMLErzeugenMBSerie in mehrere einzelne. Schon die try-except-Blöcke zeigen, dass dies besser wäre. Dann kommst du auch mit den try-except-Blöcken nicht durcheinander.
|
Re: Exception richtig behandeln
Zitat:
Der Aufbau ist ja folgendermaßen..
Delphi-Quellcode:
Hinter diesen einzelnen Funktionen, zumindstend hinter Save und EMail sind ja schon Funktionen hinter verborgen. und Öffnen und Drucken sind ja nur ShellExecute Anweisungen.
Button.Click;
//HTMLErzeugen wird aufgerufen //HTMLErzeugen erstellt die Datei aus einer Datenbank //und ruft anschließend die Funktionen //Speichern //Senden //Öffnen //hintereinander auf.
Delphi-Quellcode:
{HTML-Datei für MB-Serie erstellen}
procedure THTMLExportForm.HTMLErzeugenMBSerie; Var slHTML : TStringList; i : integer; mrResult: Integer; FileName : String; begin try try slHTML := TStringList.Create; slHTML.Add('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'); slHTML.Add('<html>'); slHTML.Add('<head>'); slHTML.Add('<link rel="stylesheet" type="text/css" href="MB.css"'); slHTML.Add('<Style type="text/css"></style>'); slHTML.Add('<title>Protokolldatei</title>'); slHTML.Add('</head>'); slHTML.Add('<body>'); slHTML.Add('<img src= ".\Kopf1.bmp" width= "900" height= "150" align= "rigth" alt= "Titel" >'); slHTML.Add('<h1 style="color:#FFFFFF; background-color:#000080; align= "right">Firma hartmann & uebach Nachrichtentechnik GmbH</h1>'); slHTML.Add('<h1 style="color:#000080;">Objekt: ' +QryVorgabe.FieldByName('KUNDEOBJEKT').AsString+'</h1>'); slHTML.Add('<table border="0" style="border-collapse:separate;"'+ 'width="100%" style="'+ 'border-left:5px solid #000080;border-right:5px solid #000080;'+ 'border-top:5px solid #000080;border-bottom:5px solid #000080;>'); slHTML.Add('<tr>'); slHTML.Add('<th align="left">Protokolldatei vom '+DateTimeToStr(Now)+'</th>'); slHTML.Add('<th align="left">ID</th>'); slHTML.Add('<th align="left">LfdNr</th>'); slHTML.Add('<th align="left">Datum</th>'); slHTML.Add('<th align="left">Uhrzeit</th>'); slHTML.Add('<th align="left">Ereignis</th>'); slHTML.Add('<th align="left">Teilnehmer</th>'); slHTML.Add('<th align="left">Bereich</th>'); slHTML.Add('<tr>'); for i := 0 to QryHTML.RecordCount -1 do begin slHTML.Add('<tr class="' + QryHTML.FieldByName('Ereignis').AsString + '">'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('ID').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(IntToStr(QryHTML.FieldByName('LfdNr').AsInteger)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(DateToStr(QryHTML.FieldByName('Datum').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(TimeToStr(QryHTML.FieldByName('Uhrzeit').AsDateTime)); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Ereignis').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Teilnehmer').AsString); slHTML.Add('</td>'); slHTML.Add('<td>'); slHTML.Add(QryHTML.FieldByName('Bereich').AsString); slHTML.Add('</td>'); slHTML.Add('</tr>'); QryHTML.Next; end; slHTML.Add('</table>'); slHTML.Add('</body>'); slHTML.Add('</html>'); except on e : Exception do begin TForm1.Servicememo.Lines.Add(e.Message); raise; end; end; try FileName := SaveHTML(slHTML); except on e : Exception do begin e.Message := 'Datei konnte nicht gespeichert werden'#13#10+e.Message; raise; end; end; try if AnzeigenCheckBox.Checked then ShellExecute(Application.Handle, 'open', PAnsiChar(FileName), nil, nil, SW_ShowNormal); except on e : Exception do begin e.Message := 'Datei konnte nicht geöffnet werden'#13#10+e.Message; raise; end; end; try if VersendenCheckBox.Checked then SendMail(FileName); except on e : Exception do begin e.Message := 'Datei konnte nicht als E-Mail versendet werden'#13#10+e.Message; raise; end; end; try if DruckenCheckBox.Checked then ShellExecute(handle, 'print', PAnsiChar(FileName), '', '', SW_HIDE); except on e : Exception do begin e.Message := 'Datei konnte nicht gedruckt werden'#13#10+e.Message; raise; end; end; finally slHTML.Free; end; end; |
Re: Exception richtig behandeln
So wie du das machst führst du die Strukturierteausnahmebehandlung ad absurdum. Normalerweise geht es so:
Delphi-Quellcode:
Lösung für dich: Deklarier dir eigene Exceptions, die in den Unterfunktionen geworfen werden:
try
Anweisung; Anweisung; Anweisung; Anweisung; Anweisung; Anweisung; except Fehlerbehandlung; end; ESaveError, ELoadError, ESendMailError, ... Und dann:
Delphi-Quellcode:
ShellExecute wirft übrigens keine Exceptions, da es eine Windows API-Funktion ist. ShellExecute liefert einen Fehlercode zurück.
try
FileName := SaveHTML(slHTML); SendMail(FileName); ...; except on E: ESaveError do ...; on E: EOpenError do ...; end; |
Re: Exception richtig behandeln
Code-Beispiel:
Delphi-Quellcode:
program Project3;
{$APPTYPE CONSOLE} uses SysUtils; type EDoSomething = class(Exception) end; EDoSomeMore = class(Exception) end; procedure DoSomething; begin raise EDoSomething.Create('Fehler in DoSomething'); end; procedure DoSomeMore; begin raise EDoSomeMore.Create('Fehler in DoSomeMore'); end; begin try DoSomething; DoSomeMore; except on E: EDoSomething do Writeln(E.Message); on E: EDoSomeMore do Writeln(E.Message); // alle anderen Exceptions on E: Exception do Writeln(E.Message); end; Readln; end. |
Re: Exception richtig behandeln
Hallo Michael,
das mit den einzelnen Exception Behandlungen habe ich verstanden. Gute Sache, da wäre ich nie darauf gekommen das so zu machen. Vorallem kann ich ja auch so die einzelnen Behandlungen eventuell noch in USER-Verständliche Sprache in denn jeweiligen Exception übersetzen. Allerdings, verstehe ich eine Sache nicht so ganz. Was machen die letzten Zeilen :gruebel:
Delphi-Quellcode:
on E: Exception do
Writeln(E.Message); end; Readln; end. Zitat:
Ansonsten danke, coole Idee. Werde das nach dem umsetzen aufjedenfall nochmal hier einstellen. Gruß Jens |
Re: Exception richtig behandeln
Steh doch im Kommentar: Sie fängt alle anderen Exceptions ab, die auftreten können. Können keine auftreten, kann das weggelassen werden.
Manche Exceptions musst du nicht neu definieren. Du kannst auch welche nehmen, die schon definiert sind un der SysUtils.pas. Mit meiner Lösung wirst du die ganzen Exception Blöcke los und die Exceptions werden da geworfen, wo sie auch auftreten. |
Re: Exception richtig behandeln
Sorry,
ich versteh eigendlich nur den Sinn von
Delphi-Quellcode:
Gruß Jens
end;
Readln; end. |
Re: Exception richtig behandeln
Ach so. Das Readln wartet auf eine Eingabe. Dann geht die Konsole nicht gleich zu, wenn man das Programm aus dem Explorer startet. Ist nur da, damit man noch die Ausgabe sieht.
Zitat:
![]() |
Re: Exception richtig behandeln
Danke Michael, :thumb:
jetzt kann ich Arbeiten. Ich habe das jetzt verstanden. :idea: Zitat:
Gruß Jens |
Re: Exception richtig behandeln
Natürlich kannst du die eigenen Exception-Klassen jetzt noch mit eigenen Methoden ergänzen -- ganz nach deinem Bedürfnissen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:43 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz