Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi RecordCount synchronisieren zwischen ibQuery und ibtable (https://www.delphipraxis.net/81509-recordcount-synchronisieren-zwischen-ibquery-und-ibtable.html)

Darkchild 28. Nov 2006 13:43

Datenbank: Firebird • Version: 1.5 • Zugriff über: Interbase

RecordCount synchronisieren zwischen ibQuery und ibtable
 
Hallöle,

ich habe da mal wieder ein Problem, wie so oft, leider :oops: .

folgendes:
Ich habe eine Maske mit einem cxdbgrid, die Daten welche ich dort Anzeige werden mir von meiner IBQuery (ibqueryzeiterfassungansicht) geliefert.
Jetzt ist es über das cxdbGrid möglich verschiedene Filter auf die Datensätze anzuwenden und eine dementsprechende Auswahl an verschiedenen Datensätzen Anzeigen zu lassen.
Jetzt möchte ich einen Count auf diese Datensätze Anwenden um zu wissen wieviele Datensetzte vor dem Filter oder auch danach jetzt noch zu sehen sind.
Denn mit diesem Ergebniss ist es geplant dann später einen weiteren durlauf durch die Datensätze zu machen und in einem Feld in der IBTable einen Wert zu schreiben (wäre das Feld gesperrt welches dann denn Wert 1 bekommen würde).
Jetzt sollen aber diese die Werte in die Table geschrieben werden und nicht in die Query, das bedeutet ich muss beide miteinander synchronisieren und genau das will mir nicht gelingen.

Nur auf der Table einen Count durchzuführen geht ohne Probs, habe ich wie folgt gemacht:
Delphi-Quellcode:
procedure Tfrmzeiterfassunguebersicht.cxbtndatensperrenClick(Sender: TObject);
var
counterrecord:integer;
begin
DataModuleMain.datasourcezeiterfassung.DataSet.First;
    while not DataModuleMain.ibtablezeiterfassung.Eof do
      begin
      counterrecord := DataModuleMain.ibtablezeiterfassung.RecordCount;
      DataModuleMain.ibtablezeiterfassung.Next;
      end;
ShowMessage(inttostr(counterrecord));
end;
Der obengezeigte Quellcode Funktioniert auch, nur das er immer alle Datensätze aus der Table nimmt und natürlich nicht die gefilterten wie im cxdbGrid zu sehen welche aus der Query kommen.

Habe dann Probiert die ganze Geschichte zu synchronisieren und zwar so:
Delphi-Quellcode:
DataModuleMain.dsqueryzeiterfassungsansicht.DataSet.First;
    while not DataModuleMain.ibqueryzeiterfassungansicht.Eof do
      begin
      DataModuleMain.ibqueryzeiterfassungansicht.Locate('zeiterfassung_id', DataModuleMain.ibtablezeiterfassungZEITERFASSUNG_ID.value,[]);
      counterrecord := DataModuleMain.ibtablezeiterfassung.RecordCount;
      DataModuleMain.ibqueryzeiterfassungansicht.LocateNext('zeiterfassung_id', DataModuleMain.ibtablezeiterfassungZEITERFASSUNG_ID.value,[]);
      DataModuleMain.ibtablezeiterfassung.Next;
      end;
ShowMessage(inttostr(counterrecord));
Habe dann mal das eine Locat und dann das andere auskommentiert aber das ergebniss war stets das selbe und zwar wenn ich im Debugger mit dem gesetzten haltepunkt die sache durchlaufe und immer brav F8 drücke läuft er durch und zählt(weiss zwar nicht ob er das dann so macht wie ich möchte , aber er zählt erstmal) ist der Haltepunkt weg und die Anwendung läuft normal und ich Starte die Geschichte, dann hängt sich die Anwendung gnadenlos weg und ich muss schauen das ich diese per TaskManager beende oder irgendwie anders daraus komme.

Hat jemand schonmal ähnliches versucht und weiss wie es geht oder hat einen Tipp oder, oder oder.... ?
Denn ich habe im Moment leider keine Idee was ich dort anders machen muss.

Über ein wenig Hilfe würde ich mich wie immer sehr freuen.

Gruss
Darkchild

dataspider 28. Nov 2006 14:26

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
Hi Darkchild,

oh oh - dein Code...

Also erst mal folgendes.
In deinem ersten Codeschnipsel läßt du dir in einer Schleife immer wieder den selben Wert geben.

Warum den Wert 10000 mal holen, nur weil 10000 Records da sind. Das tut es auch:
Delphi-Quellcode:
procedure Tfrmzeiterfassunguebersicht.cxbtndatensperrenClick(Sender: TObject);
begin
  ShowMessage(inttostr(cDataModuleMain.ibtablezeiterfassung.RecordCount));
end;
Jetzt zur TcxGrid.
Diese kennt 2 Modi, und die sind sehr wichtig!
GridMode := True und GridMode := False.
Ohne GridMode (Standard) lädt die Grid alle Records aus der DB in einen eigenen Speicher und filtert, sortiert, gruppiert etc. mit den eigenen Daten.
In diesem Mode ist Alles einfach und Alles möglich. (Gruppierung, Summierung etc.)
Der Nachteil ist, dass der Server mächtig zu tun bekommt, denn er muss alle Records liefern. Und das DataSet (Query) ist nicht synchron mit den Daten der Grid.
Bei grösseren Datenmengen sollte man also im GrideMode arbeiten. Hier muss man zum Sortieren und Filtern etwas Hand anlegen. Dazu kann man erst mal die GrideMode - DEMO studieren.
Hier ist die Datenmenge der Grid mit der Query immer synchron. Nachteil: Gruppieren und Gruppensummen sind nicht mehr möglich.

Du musst also erst mal die entscheidende Frage klären, GridMode oder nicht.

IMHO sollte der DataController der Grid den Recordcount für die Daten der Grid liefern.
Na ja, ist ein schwieriges Thema, aber die Hürde sollte man erst mal nehmen.

Cu, Frank

Darkchild 28. Nov 2006 14:43

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
@dataspider

Hm,

ok das mit dem counter ist klar kann also auch aus den 2 Zeilen 1 machen, soweit so gut und danke zunächst einmal für diesen Tipp, aber jetzt habe ich noch mal ne Frage ob ich das alles richtig verstanden habe mit der Query, der Table und dem Grid.

Im Augenblick ist es so das in dem betreffenden cxGrid die Guppierung usw. über das Drag & Drop der Colums laufen, sowie verschiedene Footer die mir bestimmte Ergebnisse summieren und Anzeigen.

Kurz mal abschweifen:
Das Zählen der Datensätze und das zuweisen des Wertes für gesperrt und das damit verbundene sperren funktioniert bei mir und es sind vieleicht mit allem 30 Zeilen Quellcode. Klappt aber im Augenblick nur wenn ich direkt auf die Table zugreife und auch nur mit allen Datensätzen oder mit keinem, daher hier auch meine Frage im Thread.

So weiter geht's:
Wenn ich Dich jetzt gerade richtig verstanden habe kann ich mich jetzt entscheiden ob Gruppierung über Colums, Footer und Summenbildung oder das Sperren von im Grid ausgewählten Datensätzen, aber beides zusammen geht nicht ?

Habe ich das richtig verstanden ? :?:

Das wäre nämlich ziemlich ungünstig für die Gesamtfunktionalität der Anwendung. :(

Gruss
Darkchild

dataspider 28. Nov 2006 16:12

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
Hi,

ich weiss nicht, ob ich dein Problem richtig verstanden habe.
Ich denke, du willst die Datenmenge durchlaufen, die in der Grid angezeigt wird.
Da du nicht im Gridmode arbeitest, musst du mit dem DataBinding.DataController arbeiten.
Da gibt es den Recordindex, über den du die Id mit GetRecordId(RecordIndex) ermitteln kannst, sofern du ein KeyField mit deinem PK definiert hast.

Aber wie gesagt, ich verstehe das Problem noch nicht ganz.

Cu, Frank

hoika 28. Nov 2006 17:43

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
Hallo,

Delphi-Quellcode:
DataModuleMain.dsqueryzeiterfassungsansicht.DataSet.First;
    while not DataModuleMain.ibqueryzeiterfassungansicht.Eof do
      begin
      DataModuleMain.ibqueryzeiterfassungansicht.Locate('zeiterfassung_id', DataModuleMain.ibtablezeiterfassungZEITERFASSUNG_ID.value,[]);
      counterrecord := DataModuleMain.ibtablezeiterfassung.RecordCount;
      DataModuleMain.ibqueryzeiterfassungansicht.LocateNext('zeiterfassung_id', DataModuleMain.ibtablezeiterfassungZEITERFASSUNG_ID.value,[]);
      DataModuleMain.ibtablezeiterfassung.Next;
      end;
ShowMessage(inttostr(counterrecord));
Finster ;) :wall:

Also du fängst mit einem DataSource(ds).DataSet.First an,
dann ein while no Query.EOF
und zum Schluss ein IBTable.Next.

Du produzierst hier ne Menge DB-Code, denke ich mal.
Zum zählen nimmt man immer noch Select Count(*)
Ich würde mir mal das ganze im SQL-Monitor ansehen.

Wenn die Daten nach zeiterfassung_id sortiert sind,
und du die noch nachfolgenden Daten haben willst,
wäre das also ein select count(*) from table where zeiterfassung_id>:DeineID

Das "DataModuleMain.dsqueryzeiterfassungsansicht.DataS et.First;"
ist auch nicht so gut, falls das ds wirklich ein DataSource ist,
was an einer Komponente hängt.
DisableControls fehlt dann, sonst wird die Komponente gezwungen,
durch deinen Code jedesmal ihre Anzeige zu aktualisieren.

Wenn es geht, ersetze die TIBTable komplett,
die ist nur aus "Kompatibilität" da und etwas lahm.


So, Feierabend ! :cheers:


Heiko

Darkchild 29. Nov 2006 06:57

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
@Dataspider

Morgen,

versuche nochmal mein Problem genau zu erklären, obwohl das leider garnicht so einfach ist.

Also, ich habe eine (alle namen nur als Beispiel) TForm_Zeiterfassung, in dieser TFormZeiterfassung liegt ein CXDBGrid (Grid von DevExpress), welches an einer IBQueryZeiterfassungsansicht gekoppelt ist. Das Grid befindet sich an einer Query damit ich halt alle Daten die in dieser Maske zu sehen seien sollen Angezeigt bekomme, da diese aus verschiedenen Tabellen kommen.

So, jetzt ist es ja über das cxdbGrid möglich über die Colums zu Filtern, z.B. einen einzelnen Namen Anzeigen lassen oder den Custom Filter benutzen und sich einen Bestimmten Zeitraum von allen dort eingetragenen Mitarbeitern anzeigen zu lassen usw. .
Jetzt bezieht sich dieser Filter ja nun auf die ans Grid angeschlossene IBQuery, wenn jetzt diese Datensätze gefiltert wurden möchte ich einen wert in ein Feld schreiben (in das Feld gesperrt soll dann nach drücken des Buttons eine 1 eingetragen werden)in die soeben gefilterten Datensätze, nur das der Wert nicht in die Query soll sondern in die zugehörige TTable_Zeiterfassung die noch etwas andere Felder besitzt, aber unteranderem auch das Feld Zeiterfassungs_ID, sowie auch das Feld Gesperrt usw.

Die Ansicht der Query aktuallisiert sich ja nur aus den dort eingetragenen TTablen nur soll der Wert gesperrt = 1 nur in die Datensätze in der Table_Zeiterfassung geschrieben werden, welche in der cxdbGrid - Anischt mit der dort Angeschlossenen IBQuery zu sehen sind nach dem Filtern.

Bei mir ist es im Augenblick so das die Datensätze gesperrt werden, aber leider immer alle und nicht nur die die im Grid über die Query mit den Filtern und Groupierungen des cxdbGrid ausgewählt wurden.

Muss dann ja irgendwie so gemacht werden das die Datensätze die im Grid angezeigt werden gelesen werden, dann jeder einzelne mit den Datensätzen aus der IBTable_Zeiterfassung verglichen wird, wurde eine Übereinstimmung gefunden, dann trage in der Table in den gefundenen Datensatz in das Feld gesperrt den Wert = 1 ein. Stimmen die beiden vergleichsdatensätze nich überein dann nehme den nächsten bis zu einer weiteren übereinstimmung und dann trage wieder in den Datensatz der in der Table steht(nicht in der Query) den Wert = 1 in das Feld gesperrt ein.

Hoffe das ist einigermassen verständlich geschrieben, ist noch früh, da klappt das mit dem formulieren noch nicht so gut, erstmal eine Cola trinken, eine Rauchen und dabei in ruhe wach werden :-D .

Gruss
Darkchild

alzaimar 29. Nov 2006 07:23

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
Also das Problem ist ein Allgemeines, und in der Architektur von Client-Server-Anwendungen begründet.

Blöderweise hilft Dir diese Erkenntnis nicht.

Du kannst versuchen, deine View (also das, was Du im Grid siehst), über einzelne TIBTable und Master-Detail-Verknüpfungen nachzubauen. Wenn Du dann an einer Tabelle etwas änderst, werden diese Änderungen auch in der zusammengeklickten 'View' sichtbar. Blöderweise hebelt man dadurch die Vorteile eines SQL-Servers aus, nämlich das extrem schnelle Suchen und Bereitstellen von Daten.

Wir haben einen anderen Ansatz verfolgt: Unsere Daten sind in einem TdxMemData, Du kannst aber auch ein TcxCustomDataSource ableiten. Wenn wir jetzt Änderungen an einer der diesen Daten zugrundeliegenden Tabellen posten, ändern wir diese Daten imn TdxMemData (oder TcxCustomDataSource) eben 'von Hand'. Das ist natürlich ziemlich bescheuert, aber anders bekommen wir das nicht hin.

Wir ziehen also die Daten vom Server und wissen ganz genau, wann welcher Record verändert werden muss. Eben weil wir in der Update-Logik die komplette View nachgebaut haben.

Wir haben zudem ein Messaging-System (TCP), sodaß die Änderungen von anderen Workstations auch auf allen Clients unmittelbar sichtbar werden, ohne das Jemand auf die Refresh-Taste haut.

Wie Du siehst, sind das aber alles Frickellösungen, eine allumfassende Lösung zu diesem Problem gibt es imho nicht. Denn der Traum, nämlich das die Query (also die View) glaskugelartig genau die Datensätze neu lädt, die sich verändert haben, ist so nicht realisierbar.

Für einen konkreten, speziellen Fall ist das aber sicherlich möglich.

dataspider 29. Nov 2006 07:59

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
Hallo Darkchild,

mal sehen, ob ich helfen kann.
Mit der folgenden Methode durchläufst du die gefilterten Records der Grid und ermittelst die ID:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
Var
  i : Integer;
  ID: Integer;
begin
  with cxGridView.DataController do
  begin
    for i := 0 to FilteredRecordCount - 1 do
    begin
      // ID ermitteln anhand des Index
      ID := GetRecordId(FilteredRecordIndex[i]);
      // Jetzt am Besten eine SP zum Setzen von gesperrt auf Feld mit dieser ID
    end;
    // und jetzt ein Refresh auf die Table
    // das Refresh ist ausreichend, wenn die Table mit der Query eine gemeinsame Transaction benutzt.
    // Sonst wäre ein CommitRetaining der SP und der Table notwendig.
  end;
end;
Voraussetzung ist, dass du das Feld mit der eindeutigen ID in der Grid einträgst:
Delphi-Quellcode:
cxGridView.DataController.KeyFieldNames := 'zeiterfassung_id';
das geht auch im OI.
Ich denke, wenn du die zeiterfassung_id hast, kommst du weiter.

Wenn ich in der Grid eine Abfrage mit mehreren Tabellen habe und benötige Änderungen, erzeuge ich auf der DB einen Updateable View. Da kannst du über Trigger steuern, wie in welchen Tabelle Werte eingetragen werden.

Cu, Frank

Darkchild 29. Nov 2006 08:19

Re: RecordCount synchronisieren zwischen ibQuery und ibtable
 
@alzaimer & Dataspider

Zunächstmal "Danke für eure Hilfe" :cheers:
Scheint aber als wäre das Problem größer als von mir zunächst eingeschätzt, aber nun gut jetzt ist es da un muss dummerweise von mir bewältigt werden.

Werde mal sehen wie weit ich mit den ansätzten die Ihr mir gegeben habt komme.
Aber ein paar Sachen davon sollten mir aufjedenfall ein Stück weiterhelfen um der Lösung wieder ein Schritt näher zu kommen.

Also nochmal THX an euch zwei.

Gruss
Darkchild


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:54 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