![]() |
Anwendungsdesign: Datenbankanwendung, Refresh.
Hallo,
wie würdet Ihr folgendes Problem designen: Verwendung von Standardkomponenten in Delphi. => DBGrid, DBNavigator, Query. --- Der Nutzer hat im DBNavigator die Möglichkeit, Query.Refresh zu drücken. Dabei ist unbekannt, wie lange das Query dauert. Nehmen wir mal an >5 Sekunden (zB Anbindung über DSL), somit kommt von Windows "diese Anwendung reagiert nicht mehr". --- Ich möchte dabei keinerlei Logik in der Form haben, da dies ja an jeder Stelle der Software, wo es einen DB-Navigator gibt, genauso passieren kann. --- Grundsätzlich hätte ich jetzt überlegt beispielsweise mein Query abzuleiten und im "BeforeRefresh" eine Thread zu starten und im "AfterRefresh" zu stoppen. In diesem sagt man der Anwendung (bzw Windows) "warten auf query, alles iO", wodurch die Meldung von Windows "Anwendung reagiert nicht mehr" verhindert wird. Für diesen Ansatz scheint es aber keinerlei technische Möglichkeit zur Umsetzung zu geben, ist das richtig? |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Delphi ist ganz klar auf eine 2-Tier-Architektur aufgelegt.
Hier die Anwendung, dort der Datenbankserver. Alle Methodenaufrufe sind synchron, d.h. blockierend. (Ich verallgemeinere hier jetzt etwas, aber das sind ganz grob die Eigenschaften von Delphi) Wenn man das ändern möchte, müsste asynchrone Funktionen in Delphi einführen oder andere Klimmzüge ausführen die einem das Leben als Programmierer vermiesen. Ausserdem müssten die Datenbanktreiberschichten ebenfalls überarbeitet werden. Wenn man Tabellen mit vielen Datensätzen anzeigen möchte, muss man einen Filter davorschalten um die Datenmenge einzuschränken. Der Benutzer muss also irgendwelche Einschränkungen (z.B. Datumsbereich) vorgeben, bevor er die Daten zu sehen bekommt. Bei den ADO-Komponenten kann man bei manchen Servern (eigentlich nur MS SQL-Server) die CursorLocation auf
Delphi-Quellcode:
stellen.
clUseServer
Dann kehrt die Abfrage relativ schnell mit Daten zurück, aber das Scrollen im DBGrid wird dafür sehr langsam (weil im Hintergrund Daten nachgeladen werden). Ausserdem wird der Server ziemlich stark beansprucht. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Zitat:
Bei ADO gibt es aber auch noch die asynchrone Verarbeitung. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
das unterstützen eigentlich viele datenbanken => cursor fetch.
die anwendung soll ja wegen mir im einfachsten fall auch blockiert sein, der nutzer wartet auf daten. aber es muß doch irgendwie möglich sein, dass diese nicht "frozen" ist (und man zB funktionen wie serverseitiges beenden der abfrage über eine 2. connection ermöglicht), ohne die komplette struktur per hand zu implementieren (da man dann ja zB sämtlichen DB-Sensitiven elemente wegwerfen kann, die datenbank operationen anstossen). gerade mit internet, cloud etc. ps - ich kann mir nicht vorstellen, das jede plunder app auf meinem telefon multithreaded ist, während der cursor kreist, nur weil evtl gerade meine internetverbindung langsam ist, damit nicht kommt "anwendung reagiert nicht mehr". Scheint ja zB Android ebenso zu machen: ![]() |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Das generelle Problem ist die Tatsache, das die anzuzeigenden Daten offensichtlich übertragen werden müssen. Müssen sie? Mehr als 100 Datensätze sieht man eh nicht auf einmal.
Ich würde einen Paging-Mechanismus implementieren oder entsprechende Komponenten (DevExpress, ServerMode) einsetzen. Sorgt einfach dafür, das die Sanduhr beim Anzeigen von Daten nicht kommen muss. Es ist für einen Server im Mehrbenutzerbetrieb auch nicht gerade prickelnd, irgendwelche Gigabytes zu schaufeln, die sich eh keiner anschaut. Der geht überflüssigerweise in die Knie. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Hallo,
Telefon-Apps benutzen idR Webservices, um die Daten zu Laden. Das Threading läuft also dort wohl auf der Middle-Tier Serverseite. Heiko |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
das ist nicht möglich, teilweise braucht die datenbank solange. oder zB eine 10 jahresauswertung und man weiß auch nie, welche interessanten einschränkungskriterien der nutzer eingibt.
nimm mal das bsp einer aussenstelle via vpn über dsl anbindung an. man kann doch nicht die komplette anwendung umprogrammieren, nur weil ich eine langsame verbindung habe. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Wo ich gerade schon mal über
![]() Abfrage im Thread laufen lassen und das Ergebnis in einem TClientDataSet zur Verfügung stellen. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
nehmen wir mal ein einfaches post an, was gerade hängt. ausgelöst durch db edit. oder halt applyupdates, what ever. es gibt tausende möglichkeiten, wann eine netzwerkanwendung hängen kann, insb. bei langsamen netzwerken. und das sind auch stellen, wo manchmal nur ein einziger datensatz ausgetauscht wird.
also gibt es hier wirklich keine möglichkeit die anwendung für windows "am leben" zu halten? letztendlich kann ja bereits ein einfaches TIdHTTP.Post; "hängen..." (wobei ich jetzt nicht mehr weiß, ob das durch "idAntiFreeze", oder wie das hieß, aufgehoben wird.) |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Zitat:
Und Paging übers Netz ist ja auch kein Problem. Und DAS ist keine Programmierung extra für eine langsame Verbindung, sondern eine nachhaltige. Meine Meinung. Aber gut, Du scheinst bedauernswerterweise suboptimale Software vorgefunden zu haben und musst nun damit umgehen (kenn ich doch irgendwoher). Aber wenn es denn nun mal ganz ohne Anpassung gehen muss, dann hilft nur ein Thread. Das Problem des Abbrechens eine lange dauernden Abfrage bleibt jedoch bestehen. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Zitat:
Zitat:
![]() Zitat:
Zusätzliche Layer - solche Techniken kann man sicher verwenden - führt aber natürlich auch sofort zu Geschwindigkeitseinbusen. Jedoch weiß ich prinzipiell auch hier nicht, wie lange es braucht. Spielt auch keine Rolle, jeder Netzwerktraffic kann mal hängen, egal wieviele Daten. Zitat:
Letztendlich kann ja sogar das Drucken "hängen", wenn der Printserver nicht richtig will. Da alles dies zentral über Klassen gesteuert werden kann, wenn es denn so Designed ist, weiß man die "3" Stellen, wo es dazu kommen kann. Daher könnte man dort eine entsprechende Struktur schaffen - zB ein 2. Thread welcher die Dauer mist und dann zB abbricht. Als Entwickler weiß ich natürlich nie, auf welche Ideen der Anwender kommt und kann somit auch nicht an jeder Stelle ein Multithread modell implementieren. Hinzu kommt, das manche Unternehmen in der letzten Ecke ein "Pentium 133" stehen haben, der dann plötzlich für Lagerbuchungen wiederentdeckt wurde. Schaut der sich dann die letzten 100 Lagerbewegungen am, dauert es > 5 Sekunden und es kommt "Software geht nicht richtig" Ich hätte erwartet, man kann zB über eine Nachricht (Postmessage and das BS) mitteilen, das alles iO ist und es noch etwas dauert (mehr als 5 Sekunden). Aber angenommen man hat alles in Threads, wie verfährt man dann, wenn ich nicht will, das der Anwender etwas machen kann und auch nicht weiß, wie die Anwendung gerade ausschaut (welche Forms offen sind etc). Prinzipiell hätte ich gedacht, man Disabled alle Forms, was aber wiederrum auch nicht "blind" geht, da das unter umständen modale Fensterzustände zerschiesst. Vereinfachter "WüßtCode" als Bsp:
Delphi-Quellcode:
...
TMyQuery.Refresh;override; procedure TMyQuery.Refresh; begin ApplicationController.CriticalSection.Enter;//Anwender muß auf Ergebnis warten, kein 2. mal hier hinein. ApplicationController.FormManager.DisableAllForms; Connection:=ConnectionPool.GetConnection; Self.DisableControls;//TDataSet T:=TThread.CreateAnonymousThread( procedure begin inherited; end); T.Start; ApplicationController.WaitForThread(T); EnableControls; ApplicationController.FormManager.EnableAllForms; ApplicationController.CriticalSection.Release; end; |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Wobei du dir mit CriticalSetion.Enter gleich die nächste Blockade eingebaut hättest.
Kannst du nicht einfach ein modales Fenster anzeigen, damit der Anwender sieht was passiert? Das wird dann beendet, wenn der Thread zurückkommt oder der Benutzer bricht die Aktion - wie auch immer - ab. Mach dann noch eine Verzögerung rein, damit das Fenster bei kurzen Abfragen nicht immer aufflackert. Ohne den Thread würden bei einem Refresh ja auch keine Eingaben verarbeitet. Insofern bringt das modale Fenster keinen Nachteil. Ist nur so aus dem Ärmel. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Man kann das Formular auch aktiv lassen und bei einer Korrektur der Filter/Sucheinstellungen einfach die alte Abfrage abbrechen und eine neue laden.
|
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Liste der Anhänge anzeigen (Anzahl: 1)
@Uwe - das ist auf jeden Fall auch noch einmal eine Idee.
Mich wundert es einfach nur, das es für diesen wirklichen absoluten Standardfall einfach kein standard- (getestetes) und empfohlenes Designmuster mit Standardkomponenten gibt, ohne das alles komplett selbst gebaut werden muß. Insb. da ja alles und jeder die Standardkomponenten zur Datenbankentwicklung verwendet (*der Vorteil* von Delphi) Das Problem sieht man ja bereits in der QualityCentraal Anwedung von EMB selbst, wenn man mal versucht zB 1000 Datensätze auszuwerten. (Anhang) gekrönt von einer Fehlermeldung, die es mir als Anwender unmöglich macht ältere Bugreoprts zu lesen?! (klar kann ich als Anwender jetzt wieder Datumsbereiche aufschreiben und per hand durchgehen, das akueptiert aber kein "normaler Mensch") |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
Zitat:
Aber das jeder die Standardkomponenten zur Datenbankentwicklung verwendet, stimmt imho so nicht, es wird eher mit Zeos, UniDac, AnyDAC etc. entwickelt. Und es herrscht die weit verbreitete Meinung, das datensensitive Steuerelemente mehr Sorgen als Nutzen bringen (wenn man sie zum Editieren verwendet). |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
[QUOTE=Furtbichler;1204073]
Zitat:
Insgesamt ist es allerdings eine schmerzhafte Erfahrung das wir Datensensitive Komponenten einsetzen, aber damals haben wir an RAD geglaubt....das führt dann auch immer zu FatClients und die sind im Netzwerk generell nicht so toll. In Neuen Anwendungen benutzen wir solche Dantenbanksensitiven Oberflächen Komponenten nur noch mit bedacht oder gar nicht. Wir setzen mittlerweile auf eine Lösung mit einem Applicationserver mit der Businesslogik und mittelschwere Netzwerkclients, da haben wir dann alles in der Hand. |
AW: Anwendungsdesign: Datenbankanwendung, Refresh.
hm also das kann ich nicht bestätigen, muß ich sagen.
natürlich baut man eine anwendung so, das man eine vernünftige architektur hat. unsere clients sind "so doof", das sie selbst nicht mal eine positionssumme einer rechnung berechnen können, das läuft alles serverseitig oder über zwischenschichten (nicht delphi ;) ) von den datensensitiven komponenten bin ich eigentlich sehr überzeugt, das funktioniert auch fantastisch, insb. mit devart, welches mit einigen gut gesetzten properties auch super sql statements formuliert. aber lassen wir mal diese glaubensdiskussion aussen vor. letztendlich ist ja die frage, wir designe ich eine applikation welche potentielle "hangs" verursacht so, das ich möglichst zentral diese problematik aus wenigen klassen heraus abfangen kann. mit multithread und disable/enable forms sind wir gleich wieder darauf hereingefallen, das zB zyklische hintergrundthreads die modalstati zerschossen haben. Bsp: Anwender drückt button "löschen" -> modal Backgroundthread -> DisableForms -> Refresh (dataset, indy, datasnap) -> EnableForms. Das TForm.Enabled zerlegt den Modalstatus und der Anwender kann plötzlich weiterarbeiten, woanders hinklicken, ohne die frage zu beantworten. sicher kann man auch dies wieder abfangen, nur wie gesagt - mich wundert das es kein standard entwurfsmuster in delphi für solche fälle gibt. bei uns ist das problem jetzt nicht wirklich eines, es läuft alles gut und die 3 anwender mit isdn verbindung (oder umts zb auf bautstellen) schulen wir schon so, das diese wissen woran sie sind, aber es muß doch mal ein vernünftiges entwurfsmuster geben, welches sich mit den eigenheiten der oberfläche / vcl bewährt hat. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:21 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