![]() |
Datenbank: MSSQL • Version: 16 • Zugriff über: ADO
refresh der Daten aus einer Datenbank --- aber wo ?
unsere Anwendung verwendet eine Main Connection (TADOConnection) . Diese Connection wird dann von einer Vielzahl von Unterprogrammen verwendet um Daten zu manipulieren. Die einzelnen Routinen änderen Datansätze ab , fügen hinzu ..... das Übliche halt.
Wir verwenden auch ein DB Grid + Datasource um Daten aus einer Query anzuzeigen. Wenn ich Datensätze in der Tabelle jetzt hinzufügen kommt das DBGrid damit nicht klar, Fehlermeldung " Key geändert". Der DBNavigator Refresh geht nicht mehr. ich könnte jetzt folgende machen
Delphi-Quellcode:
Gibt es eine bessere Idee allen an der Connection hängenden Datenverbindungen mitzuteilen "Achtung neue Daten" , bitte alles neu laden!!!!, oder so ähnlich :-)
MainStatusBar.SimpleText := 'refresh database ......';
ADOConnection.Connected := False; ADOConnection.Connected := true; /// /// load again /// loadListsFromDB(); |
AW: refresh der Datenaus einer Datenbank --- aber wo ?
query.close + query.open sollte reichen, die Verbindung muss dazu nicht geschlossen werden.
Eventuell reicht auch schon ein query.Refresh. Dem DBNavigator ein OnClick-Ereignis verpassen und dann
Delphi-Quellcode:
könnte aber auch ausreichen.
procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
begin if Button = nbRefresh then Query.Refresh; end; Wenn nicht dann dort etwas uneleganter
Delphi-Quellcode:
procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
begin if Button = nbRefresh then begin // Irgendwie den aktuellen Datensatz merken // und dann Query.Close; Query.Open; // und dann wieder zu dem oben gemerkten Datensatz wechseln. end; end; |
AW: refresh der Datenaus einer Datenbank --- aber wo ?
Liste der Anhänge anzeigen (Anzahl: 1)
query.refresh führt zu dieser AV Fehlermeldung .... :(
|
AW: refresh der Datenaus einer Datenbank --- aber wo ?
Hallo,
fehlt da vielleicht der Primary Key? Close/Open sollte aber gehen. |
AW: refresh der Datenaus einer Datenbank --- aber wo ?
Naja, die Meldung scheint ja eine der weniger schlimmen zu sein. Könnte man gezielt abfangen, wohlgemerkt gezielt!
Falls der Datensatz jedoch vermisst wird, muss man das wohl klären. |
AW: refresh der Datenaus einer Datenbank --- aber wo ?
Moin...:P
Meine Lieblingsfehlermeldung mit ADO und MSSQL...:thumb: Der Fehler hat sowohl nichts mit dem DBNavigator oder dem Eintragen im Grid zu tun. Er triff einfach beim Post auf. Ob die Tabellen einen PK haben (hatten alle einen) ist unerheblich. Die einzige Variante zur Lösung ist die von nahpets. 8-)
Delphi-Quellcode:
...das hällt bis zum nächsten Mal mit einer anderen Query. :roll: Manchmal half nur das neu Erzeugen der Query. :roll: Ich hab nie raus bekommen warum das so ist. ADO hat seinen Beitrag dabei.
procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
begin if Button = nbRefresh then begin // Irgendwie den aktuellen Datensatz merken // und dann Query.Close; Query.Open; // und dann wieder zu dem oben gemerkten Datensatz wechseln. end; end; Tipps: 1. Der MSSQL Server reagiert immer wieder mal alergisch auf permant offene Querys. Ein modernes DBMS sollte nie mit DB sensitiven Controls (da gehört auch das DBGrid dazu) manipuliert werden, sondern nur mit klassischen Querys mit Transaktionssteuerung. Erst Recht bei MultiUser Umgebungen. 2. Die Querys nur so lange offen lassen wie sie gebraucht werden... Create und try finally Free 3. Wenn es das Projekt zuläßt, sollte ein Umbau auf eine Objektstruktur zur Datenmanipulation helfen. Quasi Intern mit Objekten arbeiten und nur die Datenmanipulation z.B. in einem Interface ablaufen lassen. Der einzige wer die Datenbank kennt ist das Interface. :thumb: Sorry: Ich bin Fan von dieser Struktur ohne DB sensitive Controls: GUI <-> Logik <-> DB ...ich konnte es mir leider nicht verkneifen. :P ![]() :hi: |
AW: refresh der Daten aus einer Datenbank --- aber wo ?
Sehe die Tipps ähnlich wie haentschman, wollte aber hinzufügen, dass man (um nicht eine ganze Anwendung neu machen zu müssen) quasi als Quick and Dirty(?) Lösung weiter mit den Datensensitiven Controls arbeiten kann, indem man ein ClientDataset dazwischen schiebt. Dann ist zumindest die Query nicht immer offen (siehe Pkt. 1).
|
AW: refresh der Daten aus einer Datenbank --- aber wo ?
Ich sehe die Sache auch ähnlich wie haentschman. Mit autarken Queries ist man auf der sicheren Seite, aber:
Ich habe nie Probleme mit datensensitiven Komponenten gehabt. Und ich vermute, dass die Erfahrungen von h etwas mit der DB (herstellerspezifisch) zu tun haben und mit dem damaligen Stand der Technik (dieses Herstellers). Stichwort 1: Locking (row level locking). Das konnte vor Jahren nicht jeder (vielleicht auch heute noch nicht). Wenn ich also einen Datensatz ändere und dabei aus Mangel an Fähigkeiten dbseitig eine ganze Page gelockt wird, ist das sch..lecht. Stichwort 2: Clienttransaktionen; ich habe sowas nur spaßeshalber benutzt, default und produktiv war immer autocommit ohne eine einzige Zeile/Befehl, der aktiv Transaktionen verwaltet. M.E. liegt es in der Natur der Sache, Transaktionshandling ist Serverangelegenheit. Übernimmt man das im Client, bricht man erstens das Prinzip und ist 2. auf die Qualität der Komponentenimplementierung und 3. auf die Fähigkeiten der DB (siehe z.B. Stichwort1) angewiesen. Beispiel: Hab gerade angefangen, einen Datensatz zu ändern und mein Programm schmiert ab. Die DB hat nun ein Lock vom Client da rumfliegen, das garantiert nie ordentlich aufgelöst wird.. Stichwort 3: Ressourcenverbrauch / konkurriende Zugriffe: Gewisse Hersteller von RDBMS waren nie dafür berühmt, dass sie es gut können. Darauf basiert m.E. eine ganze Technologie bei denen. Je weniger meine DB kann, desto mehr muss ich sie schonen. Also bitte nur mal kurz Daten lesen oder updaten und dann wieder verschwinden. Dieses Prinzip ist zwar nicht unmodern, in mehrschichtigen Anwendungen ganz normal, bei bestimmten Anbietern hatte ich aber immer das "Gefühl", sie können es gar nicht viel besser. Das nur mal so wild in Kürze. Fazit: setzt man tatsächlich moderne RDBMS ein, kann man sehr wohl mit diesen Verfahren arbeiten. Ich gehe mal davon aus, dass viele DB Hersteller in den letzten 15 Jahren an ihrer Technik gearbeitet haben. Rowlevellocking und andere tolle Sachen sollten mittlerweile unproblematisch (vorhanden) sein. Letztlich kann ich also mit dem datensensitiven Komponenten (Delphikomponenten oder auch Third Party) robuste Anwendungen in kurzer Zeit entwickeln, also das machen, womit Delphi mal "berühmt" wurde. |
AW: refresh der Daten aus einer Datenbank --- aber wo ?
ADO und aktuallisierbare Querys geht im Prinzip aber:
Je nach Datenbank unterschiedlich und nicht immer zwingend "fehlerfrei". Was eventuell helfen könnte ist: Die ADO-Querys haben u. a. die Eigenschaft
Delphi-Quellcode:
und die Eigenschaft
CursorLocation
Delphi-Quellcode:
.
CursorType
Denen kann man beiden unterschiedliche Werte in unterschiedlichen Kombinationen zuweisen. Hier hilft es eventuell mal auszuprobieren, was bei der aktuellen Datenbank die "richtige" Kombination ist. Bei Access ist es (soweit ich mich erinnere)
Delphi-Quellcode:
Diese Kombination ist aber (aus meiner Erinnerung) bei FireBird kontraproduktiv.
Query.CursorLocation := clUseServer;
Query.CursorType := ctStatic; Wird zusätzlich noch 'ne ADOConnection genutzt, so bei der auch mal mit den Eigenschaften
Delphi-Quellcode:
und
CursorLocation
Delphi-Quellcode:
rumspielen.
IsolationLevel
Hier mal ein unrepräääsäääännnntatieeefes, abschrääääckendes Speibiel aus meinem Sourcenfundus, um eben genau das hier aktuell diskutierte Problem (halbwegs) zu umgehen:
Delphi-Quellcode:
// Hier den Datenbanktypen abfragen und die Werte für Cursor ... setzen.
// CursorLocation bei SQLite muss wohl clUseClient sein, // bei Access aber clUseServer // Hier noch testen, was bei SQLite am sinnvollsten ist. if fDBIsSQLite then begin // ctUnspecified, ctOpenForwardOnly, ctKeyset, ctDynamic, ctStatic // Diese Variante spart Arbeitsspeicher und ist schnell. // Aber es gibt keine RecNo. // Änderungen von Datensätzen nicht möglich. // con.CursorLocation := clUseServer; // Dann gibt es keine RecNo :-( // qrySQL.CursorType := ctKeyset; // qrySQL.CursorType := ctStatic; // Benötigt viel Arbeitsspeicher, deutlich mehr, als die Datenbankgröße. // Ist sehr langsam. qrySQL.CursorLocation := clUseClient; qrySQL.CursorType := ctDynamic; // qrySQL.CursorType := ctStatic; // qrySQL.CursorType := ctKeyset; // dbckOK ist 'ne TDBCheckBox dbckOK.ValueChecked := 'T'; dbckOK.ValueUnchecked := 'F'; end else if fDBIsAccess then begin qrySQL.CursorLocation := clUseServer; qrySQL.CursorType := ctStatic; dbckOK.ValueChecked := 'Wahr'; dbckOK.ValueUnchecked := 'Falsch'; end else if fDBIsPostGres then begin // Programmhänger beim Speichern neuer Datensätze. qrySQL.CursorLocation := clUseClient; qrySQL.CursorType := ctDynamic; // Programmhänger beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseClient; // qrySQL.CursorType := ctStatic; // Programmhänger beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseClient; // qrySQL.CursorType := ctKeyset; // Programmhänger beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseClient; // qrySQL.CursorType := ctUnspecified; // beendet den Datenbankprozess von PostGres beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseServer; // qrySQL.CursorType := ctDynamic; // beendet den Datenbankprozess von PostGres beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseServer; // qrySQL.CursorType := ctStatic; // beendet den Datenbankprozess von PostGres beim Speichern neuer Datensätze. // qrySQL.CursorLocation := clUseServer; // qrySQL.CursorType := ctKeyset; // Läßt bereits das Lesen von Datensätzen nicht zu. // qrySQL.CursorLocation := clUseServer; // qrySQL.CursorType := ctUnspecified; dbckOK.ValueChecked := 't'; dbckOK.ValueUnchecked := 'f'; end else if fDBIsFirebird then begin qryMaxTextverwaltungID.SQL.Text := 'SELECT GEN_ID(gen_TextverwaltungID,1) FROM RDB$DATABASE'; qrySQL.CursorLocation := clUseClient; qrySQL.CursorType := ctDynamic; dbckOK.ValueChecked := '1'; dbckOK.ValueUnchecked := '0'; end else begin // Ansonsten? qrySQL.CursorLocation := clUseClient; qrySQL.CursorType := ctDynamic; dbckOK.ValueChecked := '1'; dbckOK.ValueUnchecked := '0'; end; qryMaxTextverwaltungID.CursorLocation := qrySQL.CursorLocation; qryMaxTextverwaltungID.CursorType := qrySQL.CursorType; qryExecSQL.CursorLocation := qrySQL.CursorLocation; qryExecSQL.CursorType := qrySQL.CursorType; // Diese Kombination scheint bei FireBird und TAdoTable zu funktionieren. // Nein, nicht wirklich. // Bei einem Refresh gibt es eine Fehlermeldung. if fDBIsFirebird then begin if not tbTextVergleich.Active then begin tbTextVergleich.CursorLocation := clUseClient; tbTextVergleich.CursorType := ctUnspecified; end; if not tbTextVerwaltung.Active then begin tbTextVerwaltung.CursorLocation := clUseClient; tbTextVerwaltung.CursorType := ctUnspecified; end; end else begin if not tbTextVergleich.Active then begin tbTextVergleich.CursorLocation := qrySQL.CursorLocation; tbTextVergleich.CursorType := qrySQL.CursorType; end; if not tbTextVerwaltung.Active then begin tbTextVerwaltung.CursorLocation := qrySQL.CursorLocation; tbTextVerwaltung.CursorType := qrySQL.CursorType; end; end; |
AW: refresh der Daten aus einer Datenbank --- aber wo ?
Zitat:
4. simple (mindest-)Voraussetzungen: Ein Primärschlüssel (Der Primärschlüssel der aktuellen Datenmenge) sollte enthalten sein. Der Primärschlüssel sollte je Datensatz eindeutig sein. Es darf keine Aggregatfunktion in der Abfrage enthalten sein. "Virtuelle Spalten" dürfen nicht geändert werden (Funktionen, Nachschlagewerte, ..) Im Zweifel ein Update der Abfrage "zu Fuß" gegen den Server testen, also außerhalb des Programms. Die DB sagt dann, ob sie das kann bzw. wenn sie es nicht kann. Geht es nicht, hat man idR aber eher einen konzeptionellen Fehler in der Datenmenge/dem Vorgang. Das Problem hier war aber ja wohl nicht so sehr das Update selbst, sondern die Aktualisierung der Datenanzeige. Ggf. empfiehlt sich die Arbeit mit Bookmarks. Zu Beitrag #3. Die Fehlermeldung zeigt ja kein Access Violation, sondern lediglich eine Ausnahmemeldung. Notfalls sollte wie schon vorgeschlagen das Schließen und Öffnen helfen. Nach dem Öffnen muss der fragliche Datensatz dann per Code wieder lokalisiert werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:44 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 by Thomas Breitkreuz