Announcement

Collapse
No announcement yet.

OnUpdateRecord

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • OnUpdateRecord

    Hallo,

    ich habe ein Problem:

    Bisher bin ich zum bearbeiten von Querys nach folgendem Schema vorgegangen:

    <pre>
    - CachedUpdates auf True setzen
    - UpdateObject ein TUpdateSQL zuweisen
    - dieses mit SQL-Statements füllen
    - nachdem nun Eingaben in der Datenmenge erfolgten irgendwann Database.ApplyUdates ( [Query1]) aufrufen
    </pre>

    Jetzt habe ich eine Situation in der ich das OnUpdateRecord Ereignis nutzen will und habe festgestellt, dass zwar für jeden geänderten Datensatz nach ApplyUpdates dieses Ereignis aufgerufen wird jedoch der Datensatzzeiger seine Position nicht verändert, ich also innerhalb meiner Procedure nicht weiß für welchen Datensatz das Ereignis ausgelöst wurde.

    In dem Buch C/S-Datenbanken mit Delphi von Herrn Kosch habe ich ein Beispiel gefunden jedoch wird dort in jedem Afterpost-Ereignis ein ApplyUpdates aufgerufen und somit steht der Datensatzzeiger ja noch auf dem geänderten Record.

    Mein frage also: Kann man mit OnUpdateRecord auch mehrere geänderte Datensätze schreiben oder ist es ohnehin eine Unsitte ApplyUpdates nicht nach jeder Datensatzänderung aufzurufen???

    Vielen Dank schon mal im Voraus

    Gregor Fuhr

  • #2
    Hallo,

    das Ereignis <b>OnUpdateRecord</b> tritt für jeden betroffenen Datensatz einzeln auf, wenn zwischengespeicherte Aktualisierungen in einen Datensatz eingetragen werden. Normalerweise ist das eine Entweder-Oder-Entscheidung (entweder TUpdateSQL <b>oder</b> OnUpdateRecord). Das folgende Beispiel demonstriert, wie INSERTs, UPDATEs oder DELETEs über Stored Procedure realisiert werden:
    <pre>
    procedure TDataModuleCS.QueryORTEUpdateRecord(DataSet: TDataSet;
    UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
    begin
    case UpdateKind of
    ukModify : with StoredProcUPD_ORT do begin
    Params[0].Value := QueryORTEPLZ.Value;
    Params[1].Value := QueryORTEORT.Value;
    Params[2].Value := DataSet.Fields[0].OldValue;
    ExecProc;
    end;
    ukInsert : with StoredProcINS_ORT do begin
    Params[0].Value := QueryORTEPLZ.Value;
    Params[1].Value := QueryORTEORT.Value;
    ExecProc;
    end;
    ukDelete : with StoredProcDEL_ORT do begin
    Params[0].Value := QueryORTEORTID.Value;
    ExecProc;
    end;
    end;
    UpdateAction := uaApplied;
    end;
    </pre>
    Falls jedoch nur bestimmte Sonderfälle abgefangen werden sollen, kann man beide Techniken kombinieren, indem in den Standard-Fällen Apply aufgerufen wird:
    <pre>
    procedure TDataModule1.QueryORTEUpdateRecord(DataSet: TDataSet;
    UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
    begin
    if UpdatKind = ukInsert then
    begin
    QueryORTE.FieldByName('ID').NewValue := XXX;
    end;
    UpdateSQL1.Apply(UpdateKind);
    UpdateAction := uaApplied;
    end;
    </pre>
    Wenn es bei diesem Mechanismus Problem gibt, ist es immer eine gute Idee, zur Fehlereingrenzung eine Minimal-Anwendung (keine Master/Detail-Datenmenge; keine Zuweisung zur Laufzeit, sondern nur die Konfiguration über den Objektinspektor) zu erstellen

    Comment


    • #3
      Hallo Herr Kosch,

      erst mal vielen Dank für die schnelle Antwort, aber jetzt ist die Verwirrung bei mir Perfekt.

      Ich habe das Stück Quelltext mal um eine Zeile erweitert und verstehe das Ergebnis nicht ganz:

      <pre>
      procedure TForm1.Query1UpdateRecord(DataSet: TDataSet;
      UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
      begin

      if UpdateKind = ukInsert then
      begin
      Query1.Fields[1].NewValue := 'XXX';
      end;

      Memo1.Lines.Add ( Query1.Fields[1].NewValue + ', ' + Query1.Fields[1].AsString);

      UpdateSQL1.Apply(UpdateKind);
      UpdateAction := uaApplied;
      end;
      </pre>

      Wenn ich z.b. in der Query fünf Datensätze habe, füge einen hinzu und gehe wieder zum ersten Datensatz, jetzt Klicke ich einen Button an, der ApplyUpdates ausführt, wird der angefügte Datensatz richtig in die Datenmenge eingetragen (auch mit XXX). In meinem Memo kann ich nun beobachten, dass Fields[1].NewValue und Fields[1].AsString den Inhalt von zwei unterschiedliche Datensätze enthalten. Fields[1].NewValue gibt das eingefügte XXX zurück, Fields[1].AsString hingegen hat den Inhalt des Datensatzes auf dem mein Datensatzzeiger wirklich steht. Warum denn das????

      Comment


      • #4
        Hallo,

        angenommen, Cached Update bleiben erst mal völlig außen vor. Wenn ein Benutzer mit einer SQL-Datenbank arbeitet, erhält er nur eine Kopie der Daten, die zum Start seiner eigenen Transaktion gültig war. Solange er die SELECT-Abfrage (TQuery) nicht <b>neu ausführt</b>, sieht er immer nur die gleichen (lokalen) Daten - auch wenn andere Benutzer in der Zwischenzeit diese Datensätze geändert haben. Aus diesem Grund ist es üblich, die Datenmenge durch das erneute Ausführen der SELECT-Abfrage regelmässig aufzufrischen.

        Das Gleiche würde ich bei Cached Update nach einem ApplyUpdate-Aufruf machen, um "frische" Daten von der Datenbank zu erhalten, bei denen auch die in der Zwischenzeit vorgenommenen Änderungen (inklusive der Änderungen von anderen Benutzern) berücksichtigt werden. Nach dem erneuten Ausführen der SELECT-Anweisung sollte dann auch Fields[1].AsString den tatsächlichen (aktuellen) Wert wiederspiegeln. <br>
        Diese Unterschiede bleiben solange bestehen, bis nicht die Methode CommitUpdates vom Entwickler bzw. der VCL aufgerufen wurde.

        Comment

        Working...
        X