AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi TQuery (BDE) / TDataSet - Verständnisproblem "Modified"
Thema durchsuchen
Ansicht
Themen-Optionen

TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

Offene Frage von "Uwe Raabe"
Ein Thema von Bodenseematze · begonnen am 26. Aug 2024 · letzter Beitrag vom 29. Aug 2024
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#11

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 27. Aug 2024, 11:27
Das widerspricht jetzt völlig meinem Verständnis.
Dann empfehle ich die Studie der einschlägigen Lektüre. Obwohl nicht mehr ganz so einfach zu finden, steht in der Hilfe doch so einiges zum Thema Cached Updates drin: https://docwiki.embarcadero.com/Libr....CachedUpdates

Wohin wird das denn durch "Post" gespeichert?
Wie in der Doku erwähnt, in einen lokalen Speicherbereich, der im Format einer Paradox-Table entspricht.

Bei der ersten Änderung des Master- oder eines der Detail-Datensätze starte ich auf der Datenbank eine Transaktion - dann können soviel Änderungen durchgeführt werden wie gewünscht.
Und erst wenn alle Änderungen entweder gespeichert (Commit) oder verworfen (Rollback) werden, sind die Änderungen weg.
Bei CachedUpdates ist die Transaktions-Steuerung gar nicht involviert. Das findet ausschließlich im DataSet (TQuery) statt. Erst beim Aufruf von ApplyUpdates wird die Datenbank involviert und die Transaktion bekommt die Daten. Wenn du bereits vorher eine Transaktion gestartet hast, dann hat das lediglich Einfluss darauf, welche Änderungen von anderen Clients du sehen kannst. Deine eigenen Änderungen sind vor dem ApplyUpdates gar nicht in der Datenbank vorhanden.


Und bis dahin muss ich doch programmtechnisch feststellen können, ob sich im Master-Datensatz oder einem der Detail-Datensätze Änderungen (d.h. es sind Daten im Query ggü. dem Datenbankinhalt verändert) befinden.

Und da möchte ich eben verstehen, mit welchen Properties / Aufrufen etc. auf den TQuery / TDataSet (oder auch sonst irgendwie) ich das einfachst möglich - aber korrekt - feststellen kann...
Wenn der aktuelle Datensatz im Insert/Edit Mode ist, dann gibt Modified an ob dieser geändert wurde (gegebenenfalls erst nach Aufruf von UpdateRecord). Ergänzend dazu gibt UpdatesPending an, ob es bereits andere Änderungen an den Daten der Query seit dem letzten ApplyUpdates gegeben hat, die aber noch nicht an die Datenbank übertragen wurden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#12

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 27. Aug 2024, 14:20
Du verwendest Queries, wenn ich es richtig gesehen habe. Diese können eigene DML-Anweisungen (Edit, Delete, Insert) haben, die unter Umständen automatisch ausgelöst werden.
Bei mir sind es "normale" Selects - meistens auf DB-Views und manchmal auch mit speziellen 'generierten' Spalten (z.B. CONVERT( MONEY, [Spalte] ) AS [Spalte])

Selbst wenn keine echten Änderungen vorliegen kann es solche Situationen geben, die manchmal kaum nachvollziehbar sind.
Das scheint bei mir der Fall zu sein...

Da du sowieso mit Transaktionen arbeitest, würde ich CachedUpdates deaktivieren. Wenn du nicht gerade Massenänderungen machst, ist der Netzwerkverkehr zu vernachlässigen und in dem Fall könntest du CachedUpdates auch gezielt aktivieren.
Der Netzwerkverkehr ist nicht das Problem.
Aber: wenn ich ChachedUpdates deaktiviere, kann ich gar nicht mehr (einfach) sehen, wenn es (noch nicht per "Commit" bestätigte) Änderungen in den Queries ggü. der Datenbank gibt - und schon gar nicht, was genau geändert ist (das versuche ich nämlich auch noch optisch darzustellen - über TField-Vergleiche).
Um das ohne CachedUpdates hinzubekommen, müsste ich mir dann den ursprünglichen Dateninhalt merken (eigene ReadOnly-DataSet?) und mit den aktuellen Daten vergleichen...
Das ist irgendwie auch keine Lösung

Ich versuche jetzt mal, das durch Eure Kommentare gelernte (oder herausgefundene) umzusetzen und schaue mal, ob ich eine vernünftige Erkennung von Änderungen hinbekomme...
...weitere Anmerkungen / "Stupser" sind gern gesehen!
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.354 Beiträge
 
Delphi 11 Alexandria
 
#13

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 27. Aug 2024, 16:24
Der Netzwerkverkehr ist nicht das Problem.
Aber: wenn ich ChachedUpdates deaktiviere, kann ich gar nicht mehr (einfach) sehen, wenn es (noch nicht per "Commit" bestätigte) Änderungen in den Queries ggü. der Datenbank gibt - und schon gar nicht, was genau geändert ist (das versuche ich nämlich auch noch optisch darzustellen - über TField-Vergleiche).
Um das ohne CachedUpdates hinzubekommen, müsste ich mir dann den ursprünglichen Dateninhalt merken (eigene ReadOnly-DataSet?) und mit den aktuellen Daten vergleichen...
Das ist irgendwie auch keine Lösung

Ich versuche jetzt mal, das durch Eure Kommentare gelernte (oder herausgefundene) umzusetzen und schaue mal, ob ich eine vernünftige Erkennung von Änderungen hinbekomme...
...weitere Anmerkungen / "Stupser" sind gern gesehen!
Wenn du Transaktionen verwendest, sieht man mit InTransaction, ob das noch aktiv ist.
Um auf Feldebene zu sehen, was sich geändert hat, musst du meines Wissens immer mit der DB vergleichen. Eine Liste der betroffenen Datensätze muss in jedem Fall selbst mitführen. Ich wüsste zumindest nicht, wie man an eine Liste auf Basis von UpdatesPending kommen soll. Allerdings hatte ich auch noch nie den Bedarf. Vielleicht wäre es sinnvoll, die Daten in einem ClientDataSet zu verwalten, statt direkt mit der DB zu kommunizieren. Du willst die Daten ja sowieso erst nach Bestätigung durch den Anwender an die DB schicken. Da bietet sich so eine Zwischenschicht schon an.
Peter
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#14

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 29. Aug 2024, 10:10
Um auf Feldebene zu sehen, was sich geändert hat, musst du meines Wissens immer mit der DB vergleichen.
Ich gehe dazu ganz grob folgendermaßen vor:
- bei der Erzeugung der Maske suche ich alle Controls auf der Maske heraus, die einen Datenbank-Bezug haben
(bei denen es entweder ein Property "DataSource" oder "DataSet" gibt oder ein Property "DataField" oder "Field", die ihrerseits ein Property "DataSource" oder "DataSet" haben);
die merke ich mir samt den dazugehörigen "TFields" in einer speziellen Liste
- wenn ein "DataSource" auf der Maske den Status auf "dsEdit" setzt, durchsuche ich die Liste nach geänderten "TFields"
(bei denen prüfe/vergleiche ich Value, NewValue und ggf. OldValue)
- ist ein Feld geändert, suche ich in der o.a. Liste nach Controls, die sich auf die "DataSource" und das Feld beziehen und setze deren Fontfarbe auf "rot"

Das funktioniert relativ gut - hat noch ein paar Spezialfälle, die ich gesondert handhabe, aber im großen und ganzen funktioniert das

Vielleicht wäre es sinnvoll, die Daten in einem ClientDataSet zu verwalten, statt direkt mit der DB zu kommunizieren. Du willst die Daten ja sowieso erst nach Bestätigung durch den Anwender an die DB schicken. Da bietet sich so eine Zwischenschicht schon an.
Prinzipiell gebe ich Dir da Recht - wäre wahrscheinlich auch zunftsträchtiger (da ja dann endlich ggf. die BDE-Bezüge eliminierbar wären).
Ich habe in der Richtung auch bereits Experimente in meinem Code gemacht - bin dann dort aber auf andere Probleme gestoßen, die nicht so einfach behebbar waren --> also leider auch keine "einfache" Lösung


Aktuell habe ich in dem Zusammenhang schon wieder ein komisches Problem:
Ich will ja den korrekten Status sowohl eines einzelnen Records als auch des gesamten Queries (bzw. DataSet) bestimmen - dazu gehört auch herauszufinden, ob ein Record gelöscht wurde.
Um solche Records überhaupt im DataSet zu haben, verwende ich folgenden Code (Auschnitt):
Delphi-Quellcode:
function DSRecGetState( const ds_ : TDataSet ) : TUpdateStatus;
var
   dsBDE : TBDEDataSet;
   updRecTypes : TUpdateRecordTypes;
begin
...

  Log( ds_ ); // 1. Aufruf

  dsBDE := nil;
  if ( ds_ is TBDEDataSet ) then begin
    dsBDE := TBDEDataSet( ds_ );
  end;

  updRectTypes := [];
  if ( Assigned(dsBDE) and dsBDE.CachedUpdates ) then begin
    updRecTypes := dsBDE.UpdateRecordTypes;
    if ( NOT (rtDeleted in updRecTypes) ) then begin
      dsBDE.UpdateRecordTypes := dsBDE.UpdateRecordTypes + [ rtDeleted ];
    end;

    Log( ds_ ); // 2. Aufruf
  end;

...
end;
beim ersten Log-Aufruf kommt folgendes:
Code:
Active=true, RecordCount=1, CanModify=true, Modified=true, UpdateStatus()=Unmodified, State=dsEdit, CachedUpdates=true, UpdatesPending=false
beim zweiten Log-Aufruf kommt folgendes:
Code:
Active=true, RecordCount=1, CanModify=true, Modified=false, UpdateStatus()=Modified, State=dsBrowse, CachedUpdates=true, UpdatesPending=true

Was soll das? Wieso wird durch das Verändern des "UpdateRecordTypes"-Set der Status des einen (!) vorhandenen Records geändert?
Er veliert das Modified-Flag und auch der State des gesamten Queries geht von "dsEdit" auf "dsBrowse"!???

Lt. Doku heißt es doch:
An application might also use UpdateRecordTypes like a filter to temporarily limit visible records to those added or inserted by the user during the current session.
Das habe ich so interpretiert, dass man das problemlos während der Laufzeit ändern kann (am Ende o.a. Funktion stelle ich das auch wieder auf den ursprünglichen Wert zurück)...

Geändert von Bodenseematze (29. Aug 2024 um 10:13 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#15

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 29. Aug 2024, 11:03
Wieso wird durch das Verändern des "UpdateRecordTypes"-Set der Status des einen (!) vorhandenen Records geändert?
Er veliert das Modified-Flag und auch der State des gesamten Queries geht von "dsEdit" auf "dsBrowse"!???

Ein Blick in die Sourcen macht das klar:
Delphi-Quellcode:
procedure TBDEDataSet.SetUpdateRecordSet(RecordTypes: TUpdateRecordTypes);
begin
  CheckCachedUpdateMode;
  CheckBrowseMode;
  UpdateCursorPos;
  Check(DbiSetProp(hDbiObj(Handle), curDELAYUPDDISPLAYOPT, Longint(Byte(RecordTypes))));
  Resync([]);
end;
Delphi-Quellcode:
procedure TDataSet.CheckBrowseMode;
begin
  CheckActive;
  DataEvent(deCheckBrowseMode, 0);
  case State of
    dsEdit, dsInsert:
      begin
        UpdateRecord;
        if Modified then Post else Cancel;
      end;
    dsSetKey:
      Post;
  end;
end;
Lt. Doku heißt es doch:
An application might also use UpdateRecordTypes like a filter to temporarily limit visible records to those added or inserted by the user during the current session.
Das habe ich so interpretiert, dass man das problemlos während der Laufzeit ändern kann (am Ende o.a. Funktion stelle ich das auch wieder auf den ursprünglichen Wert zurück)...
Kann man ja auch. Es hat halt bestimmte Auswirkungen, die in der Hilfe nicht umfassend beschrieben sind. Dass diese Aktion den dsBrowse State erfordert, war vermutlich für den damaligen Author der Hilfe irgendwie selbstverständlich. Wenn man überlegt, ist das auch nachvollziehbar, da die Hilfe ja erwähnt, dass es eine Art Filter ist, und beim Ändern eines Filters könnte ja der aktuelle Datensatz aus der Anzeige rausfallen. Insofern ist ein Wechsel in den dsBrowse State schon angebracht.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
68 Beiträge
 
#16

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 29. Aug 2024, 15:03
Ein Blick in die Sourcen macht das klar:
Delphi-Quellcode:
procedure TBDEDataSet.SetUpdateRecordSet(RecordTypes: TUpdateRecordTypes);
begin
  CheckCachedUpdateMode;
  CheckBrowseMode;
  UpdateCursorPos;
  Check(DbiSetProp(hDbiObj(Handle), curDELAYUPDDISPLAYOPT, Longint(Byte(RecordTypes))));
  Resync([]);
end;
Delphi-Quellcode:
procedure TDataSet.CheckBrowseMode;
begin
  CheckActive;
  DataEvent(deCheckBrowseMode, 0);
  case State of
    dsEdit, dsInsert:
      begin
        UpdateRecord;
        if Modified then Post else Cancel;
      end;
    dsSetKey:
      Post;
  end;
end;
OK - das erklärt es, wobei das (vermutlich wg. CachedUpdates) ja immer noch nicht tatsächlich in der Datenbank angekommen ist, sondern wohl "nur" in der internen (Paradox basierten) Speichertablle, oder?
(OffTopic: eine Methode "CheckXXXX" zu nennen und dann in der Methode die Daten zu verändern, halte ich übrigens für seehr schlechten Programmierstil - und hatte ich ebenfalls beim groben durchsehen der Quellen nicht erwartet)

Wenn man überlegt, ist das auch nachvollziehbar, da die Hilfe ja erwähnt, dass es eine Art Filter ist, und beim Ändern eines Filters könnte ja der aktuelle Datensatz aus der Anzeige rausfallen. Insofern ist ein Wechsel in den dsBrowse State schon angebracht
Stimmt, der umgekehrte Weg, dass jemand ein bestehendes Flag (z.B. rtModified) aus den UpdateRecordTypes entfernt, könnte ja auch sein - habe ich mir noch gar nicht klar gemacht...

Wäre denn (anhand der o.a. Ergebnisse) für die Status-Abfrage des aktuellen Records folgendes richtiger?
Delphi-Quellcode:
Result := usUnmodified;
if ( (ds_ is TBDEDataSet) and TBDEDataSet(ds_).UpdatesPending and (ds_.UpdateStatus() <> usUnmodified) ) then begin
  Result := ds_.UpdateStatus();
else
if ( ds_.Modified ) then begin
  Result := usModified;
end;
oder einfach ganz ohne TBDEDataSet-Prüfung (da UpdateStatus() in der Basis-Implementierung und ohne CachedUpdates usUnmodified zurückliefert):
Delphi-Quellcode:
Result := usUnmodified;
if ( ds_.UpdateStatus() <> usUnmodified ) then begin
  Result := ds_.UpdateStatus();
else
if ( ds_.Modified ) then begin
  Result := usModified;
end;
Aber für die Abfrage des Status des gesamten Queries müsste dann doch tatsächlich über alle Records gelaufen werden - auf das State-Property kann ich mich da ja nicht verlassen (wenn CachedUpdates gesetzt ist), oder?

Geändert von Bodenseematze (29. Aug 2024 um 15:24 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#17

AW: TQuery (BDE) / TDataSet - Verständnisproblem "Modified"

  Alt 29. Aug 2024, 16:13
UpdatesPending ist doch für alle Datensätze außer dem aktuellen, falls er gerade editiert wird, ausreichend:

Delphi-Quellcode:
function HasSomethingChanged(ADataSet: TBDEDataSet): Boolean;
begin
  Result := ADataSet.UpdatesPending;
  if not Result and (ADataSet.State in [dsEdit, dsInsert]) then begin
    ADataSet.UpdateRecord;
    Result := ADataSet.Modified;
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:31 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz