AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Kundenliste

Ein Thema von EdAdvokat · begonnen am 14. Apr 2017 · letzter Beitrag vom 22. Apr 2017
Antwort Antwort
Seite 6 von 10   « Erste     456 78     Letzte »    
EdAdvokat

Registriert seit: 1. Mai 2016
Ort: Berlin
414 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#51

AW: Kundenliste

  Alt 18. Apr 2017, 21:12
Ich bin da erst einmal ratlos. Man kann es drehen und wenden, die procedure SaveToDB stimmt irgenwie nicht. Weder mit  for I:= Self.Count-1 downto 0 do noch mit  for I:=0 to Self.count-1 do läuft die Sache rund.
Es ist doch nicht normal, dass ein Speichervorgang von ca. 1000 Datensätzen gut 5 Minuten dauert und im Ergebnis dann 2000 Datensätze vorhanden sind, obwohl überhaupt keine Veränderung in der Datenbank vorgenommen wurde.
Das Hinzufügen einer Methode Speichern zum Objekt TCustumer würde nach meinem Verständnis bedeuten, dass ich die gleiche Procedure SaveToDB von TCustomerList hin zu TCustomer schreibe und dann aufrufen soll?
Das wäre doch das gleiche in Grün.
Möglicherweise habe ich ein Brett vor dem Kopf. Ich vermute, dass die SaveToDB-procedure eine Macke hat, egal ob for I:= 0 to self.count-1 do oder umgekehrt. Es ist doch nicht normal, dass ein solcher Vorgang gut 6 Minuten dauern soll.
Leider bin ich mit meinem Latein am Ende.
Norbert
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#52

AW: Kundenliste

  Alt 18. Apr 2017, 21:35
Es ist doch nicht normal, dass ein Speichervorgang von ca. 1000 Datensätzen gut 5 Minuten dauert und im Ergebnis dann 2000 Datensätze vorhanden sind, obwohl überhaupt keine Veränderung in der Datenbank vorgenommen wurde.
Wenn 2000 Datensätze vorhanden sind, und Du 1000 Datensätze gespeichert hast, dann waren wohl 1000 Datensätze vorhanden. Waren keine Datensätze vorhanden, ist vllt. jeder Datensatz zwei mal gespeichert worden?
Keine Veränderung in der Datenbank? also wurde nichts gespeichert und die 2000 Datensätze waren von Anfang an vorhanden?

Was die Speicherdauer angeht, das kommt ganz auf den Server und die gespeicherte Datenmenge an, aber 5 Minuten ist schon recht happig.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Hobbycoder

Registriert seit: 22. Feb 2017
930 Beiträge
 
#53

AW: Kundenliste

  Alt 19. Apr 2017, 07:08
Du hättest als erstes mal die Möglichkeit einen Haltepunkt am Anfang der SaveToDB-Routine zu setzen, und mit F8 mal schrittweise durchzusteppen. Dann schaust du dir erst mal den Wert von CustomerList.Count an, ob der überhaupt bei 2000 liegt, bzw. sich jedes mal verdoppelt.
Dann würde ich mal einen Blick auf die ID werfen. Wenn die >-1 ist, springt er auf das richtige SQL-Statement (Update)? Oder macht er womöglich immer ein insert?

Du kannst auch mal folgendes Probieren. Setze eine Haltepunkt auf die Zeile zqryMain.Params.ParamValues['ID']:=self[i].ID; . Diese wird ja nur bei einem Insert aufgerufen. Dann Programm starten, DB Laden und direkt danach wieder speichern. Da kein Datensatz neu ist, dürfte ja kein Insert auftreten und die Zeile nie angesprochen werden. Sollte das doch der Fall sein, stimmt ja was mit der ID nicht.

Weiterhin könntest du noch mal die Routine LoadFromDB anschauen. Werden da wirklich vor dem Laden alle Object von der CustomerList gelöscht (CustomerList.Clear)? Wenn nicht, würde das bedeuten, dass er immer alles Datensätze beim laden anhängt, und dann hättest du nach dem Laden immer 1000 mehr (Sofern 1000 in der DB sind).

Warum überhaupt gleich 1000 Datensätze zum Testen/Debuggen? Das macht das ganze doch eher unübersichtlich und langwierig. Fang mit einem Datensatz an. Laden, Editieren, Speicher und wieder Laden. Sind es dann 2? Auch das löschen und Hinzufügen zum testen wäre mit weniger Datensätzen schneller erledigt. Im Normalfall gilt, was mit 10 Datensätzen fehlerfrei läuft, läuft auch mit 1000 und 10000.
Vielleicht baust du dir auch eine Statuszeile ein, in der die CustomerList.Count steht, und nach jeder Aktion aktualisiert wird.

Aber damit du nicht ewig suchst, dein Fehler in der SaveToDB. Genauer beim zqryMain.sql.text:=. Wenn ID=-1 dann lädst du das Update und wenn ID>-1 dann verwendest du Insert. Das ist logischerweise verkehr herum. Beim Bestücken der Parameter machst du es dann aber wieder richtig.
Aber du hast noch andere Fehler drin, die dir später noch viel Kopfzerbrechen bereiten werden.

Geändert von Hobbycoder (19. Apr 2017 um 07:21 Uhr)
  Mit Zitat antworten Zitat
Hobbycoder

Registriert seit: 22. Feb 2017
930 Beiträge
 
#54

AW: Kundenliste

  Alt 19. Apr 2017, 07:53
Ich habe mal ein bisschen rumgespielt, und mir mal eine Zeitmessung eingebaut.

Bei 47416 Datensätzen dauert
das Laden aus der DB: 17 Sek.
das Füllen des Listview: 232 Sek.
das Speichern (mit deinem Fehler): 398 Sek. (weil ja fehlerhafterweise jeder Datensatz mit Insert neu eingefügt wird).

Damit könnte keiner arbeiten. Selbst wenn du den Fehler beseitigst, wird die Zeit für das Speichern nicht so kleiner, dass es komfortabel wäre, denn es würde ja auch jeder Datensatz trotzdem gespeichert, nur halt mit Update.

Abhilfe, bei jetzigem Programmaufbau, würde z.B. eine Hilfevariable im Customer-Object schaffen. Du könnte in der TCustomer-Klasse noch die Property Modified als Boolean einfügen, die im Constructor Create erst einmal auf False gesetzt wird.
Wird nun ein Datensatz verändert, oder hinzugefügt, so wird CustomerList[x].Modified bzw. Customer.Modified auf True gesetzt.

In der SaveToDB-Routine könntest du nun erst einmal auf Modified prüfen und so entscheiden, ob der Datensatz überhaupt gespeichert werden muss. So hättest du die Zeit für das Speichern auf wenige Sekunden oder Millisekunden reduziert. Darfst aber nicht vergessen, nach dem Speichern des Datensatzes Modified wieder auf False zu setzen.

Sinnvoll wäre auch, nach dem editieren den zugehörigen ListView-Eintrag gleich zu aktualisieren, damit nach dem SaveToDB auch wirklich das richtige im Listview steht (ist natürlich suboptimal, aber bei jetzigem Programmaufbau am sinnvollsten).

Ähnliches Problem besteht beim löschen eines Datensatzes. Zur Zeit löscht du ihn nur aus der CustomerList und machst anschließend ein FuelleListView. Damit ist er zwar aus der Liste, aber in der DB immer noch vorhanden und beim nächsten Laden wieder da.
Außerdem dauert das FuelleListView bei 47416 Datensätzen ja fast 4 Minuten. Also inakzeptabel.
Hier hättest du 2 Möglichkeiten, entweder du entfernst per SQL den Datensatz gleich aus der DB und den dazugehörigen Eintrag aus der ListView, oder du machst es wie oben mit einer Hilfsproperty, die z.B. Deleted heißen könnte. Auf die müsstest du dann aber in der SaveToDB auch eingehen, und ein passendes Delete-Statement für SQL bereitstellen.

Was die Zeit angeht, die das Listview benötigt, bis alles Daten der CustomerList dort vorhanden ist, so wird man dort wohl keine signifikante Geschwindigkeitssteigerung erreichen. Zumindest nicht mit Möglichkeiten, die du jetzt hier auch verstehen würdest. Für diesen Fall würde sich aber ein VirtualStringTree gerade zu aufdrängen. Das ist zwar vom Handling her etwas komplizierter, aber wenn man die Arbeitsweise erst mal verstanden hat, schon fast genial. Und in deinem Fall gut einsetzbar, da du bereit die passenden Objecte vorliegen hast.

Und für alle anderen, die das jetzt gelesen haben: Sicherlich gibt es wesentlich bessere Möglichkeiten das speichern der Daten so zu realisieren, damit viele der oben genannten Schritte gar nicht notwendig wären. Aber ich wollte EdAdvokat erst mal nur die Möglichkeiten und Probleme aufzeigen, ohne Ihn vollends zu verwirren.

Geändert von Hobbycoder (19. Apr 2017 um 07:57 Uhr)
  Mit Zitat antworten Zitat
EdAdvokat

Registriert seit: 1. Mai 2016
Ort: Berlin
414 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#55

AW: Kundenliste

  Alt 19. Apr 2017, 16:56
Vielen Dank für die vielen Hinweise, die ich z.T. jedoch noch nicht verarbeiten kann. Ich konzentriere mich zunächst darauf die SaveToDB-procedure ordentlich zum laufen zu bekommen und dann werde ich mich an die Hinweise zur Verbsserung des Programms machen. Meine Versuche mit dem Debugger zu arbeiten waren durchwachsen. Ich habe den Hinweis mit dem Haltepunkt beachtet und mit F8 Zeile für Zeile geprüft. Er durchlief tatsächlich nur die update-Routine und nicht Insert. Die Prüfung in der LoadFromDB ob clear tatsächlich keinen Datensatz mehr hat war für mich sehr unübersichtlich, denn ich weiss gar nicht was ich da wo suchen sollte.
Nun erst einmal zum Ergebnis SaveToDB hier die jetzige Fassung, hoffentlich richtig:
Delphi-Quellcode:
procedure TCustomerList.SavetoDB(con: TZConnection);
var
  zqryMain: TZQuery;
  i: Integer;
begin
  zqryMain:=TZQuery.Create(nil);
  try
    zqryMain.connection:=con;

for I:= 0 to self.Count-1 do
begin
   if self[i].ID>-1 then
     zqryMain.SQL.Text:='UPDATE WARENVERKAUF1 SET KDNR=:KNR, NAME =:NAM, VORNAME=:VNA, FIRMA=:FIR, PRODUKT=:PRO, ANZAHL=:ANZ, PREIS=:PRE WHERE ID=:CIDelse
     zqryMain.SQL.text:='INSERT INTO WARENVERKAUF1(KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS) VALUES(:KNR, :NAM, :VNA, :FIR, :PRO, :ANZ, :PRE)';
     zqryMain.params.parseSQL(zqryMain.sql.text, True);
   if self[i].ID>-1 then
   begin
     zqryMain.Params.ParamValues['CID']:=self[i].ID; //update
     zqryMain.params.ParamValues['KNR']:=self[i].KDNR;
     zqryMain.params.paramValues['NAM']:=self[i].Name;
     zqryMain.params.paramValues['VNA']:=self[i].Vorname;
     zqryMain.params.ParamValues['FIR']:=self[i].Firma;
     zqryMain.Params.ParamValues['PRO']:=self[i].Produkt;
     zqryMain.Params.ParamValues['ANZ']:=self[i].Anzahl;
     zqryMain.params.paramValues['PRE']:=self[i].Preis;
     zqryMain.ExecSQL;
   end else
   begin
     zqryMain.params.ParamValues['KNR']:=self[i].KDNR; //insert
     zqryMain.params.paramValues['NAM']:=self[i].Name;
     zqryMain.params.paramValues['VNA']:=self[i].Vorname;
     zqryMain.params.ParamValues['FIR']:=self[i].Firma;
     zqryMain.Params.ParamValues['PRO']:=self[i].Produkt;
     zqryMain.Params.ParamValues['ANZ']:=self[i].Anzahl;
     zqryMain.params.paramValues['PRE']:=self[i].Preis;
     zqryMain.ExecSQL;
   end;
end;

  finally
    zqryMain.Free;
  end;
end;
Damit kann ich einen hinzugefügten Datensatz(der als ID zunächst -1 hat) speichern und dann wieder laden und er hat dann eine ID der Datenbank, so wie es sein sollte. Auch das Bearbeiten eines bestehenden Datensatzes und das Speichern klappt. Nach Laden mit LoadFromDB ist der geänderte Datensatz sichtbar. Nur nach dem Löschen von Datensätzen und Speichern erscheint nach LoadFromDB oder Neustart des Programms wieder der gelöschte Datensatz. Das bekomme ich einfach nicht hin.
Ich hätte noch so viele Fragen, aber zunächst soll das Hauptproblem gelöst werden. Ist die Procedure wirklich richtig????
Im Hauptformular rufe ich mit dem Button löschen die Routine auf: CustomerList.Delete(lvCustomer.Selected.Index); hier wird doch der ausgewählte Datensatz aus der objectlist gelöscht. Danach wird fülleListview aufgerufen. Das ist doch auch i.o.
Wenn ich wüßte wie ich mit dem Debugger diese Problematik prüfen könnte. Da er ja tatsächlich auch sichtbar den Datensatz aus der Liste löscht, jedoch beim Speichern ihn wohl nicht gelöscht speichert, erscheint er danach wieder.
Norbert
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.540 Beiträge
 
Delphi 11 Alexandria
 
#56

AW: Kundenliste

  Alt 19. Apr 2017, 17:49
Und wo löschst Du den Datensatz aus der Datenbank?
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
EdAdvokat

Registriert seit: 1. Mai 2016
Ort: Berlin
414 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#57

AW: Kundenliste

  Alt 19. Apr 2017, 18:21
Zitat:
Und wo löschst Du den Datensatz aus der Datenbank?
Aus der objectlist ist er wohl gelöscht worden. Nun gehe ich davon aus (vermutlich ist das falsch) dass er mit SaveToDB dann auch in der Datenbank gelöscht gespeichert wird. Das ist wohl nicht der Fall, sonst würde er nach LoadformDB nicht wieder erscheinen. Er wird also nicht gelöscht. Mit meinen bescheidenen Debuggerversuchen habe ich festgestellt, dass die INSERT-Zeile nie angesprugen wird auch wenn ich einen neuen Datensatz eingebe wird stets UPDATE aufgerufen. Das ist doch auch so nicht ok.?!
Wenn ich das Problem hier gelöst habe, werde ich erst einmal abtauchen und mich mit verschiedenen grundlegenden Fragen beschäftigen. Doch leider braucht man für viele "dumme und naive" Fragen die Hilfe, die hier im Forum tatsächlich gegeben wird. Ich danke allen dafür auch wenn es mit mir so manches Mal nervig ist. Es tut mir leid und ich will nicht aufdringlich sein, doch so kurz vor dem Ziel möchte ich nicht aufgeben, auch wenn ich Stunden und Tage an so einem verfluchten Ding sitze und einfach nicht weiter komme.
Was mache ich falsch?
Ist die Prochedure SaveToDB in der letzten Fassung so richtig??????
Warum wird Insert nie aufgerufen????
Norbert
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#58

AW: Kundenliste

  Alt 19. Apr 2017, 20:24
[QUOTE=EdAdvokat]
Zitat:
Warum wird Insert nie aufgerufen????
Diese Frage verstehe ich nicht, in Deinem vorhergehenden Beitrag hast Du geschrieben, dass Datensätze mit id = -1
gespeichert werden und eine Id bekommen - das entspricht doch dem insert - oder?

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
EdAdvokat

Registriert seit: 1. Mai 2016
Ort: Berlin
414 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#59

AW: Kundenliste

  Alt 19. Apr 2017, 21:04
ich verzweifele: obwohl beim Hinzufügen die ID mit -1 ausgewiesen wird geht das Programm (Debugger) beim Speichern (SavetoDB) in den Bereich UPDATE????
Was ist hier los? Es sollte doch bei -1 nach INSERT gehen. Was mache ich wohl falsch??? Stimmt die Procedure SaveToDB???????
Habe es jetzt neu gefasst:
Delphi-Quellcode:
procedure TCustomerList.SavetoDB(con: TZConnection);
var
  zqryMain: TZQuery;
  i: Integer;
begin
  zqryMain:=TZQuery.Create(nil);
  try
    zqryMain.connection:=con;
for i := 0 to self.Count-1 do
begin
  if self[i].ID>-1 then
  begin
     zqryMain.SQL.Text:='UPDATE WARENVERKAUF1 SET KDNR=:KNR, NAME =:NAM, VORNAME=:VNA, FIRMA=:FIR, PRODUKT=:PRO, ANZAHL=:ANZ, PREIS=:PRE WHERE ID=:CID';
     zqryMain.params.parseSQL(zqryMain.sql.text, True);
     zqryMain.Params.ParamValues['CID']:=self[i].ID; //update
     zqryMain.params.ParamValues['KNR']:=self[i].KDNR;
     zqryMain.params.paramValues['NAM']:=self[i].Name;
     zqryMain.params.paramValues['VNA']:=self[i].Vorname;
     zqryMain.params.ParamValues['FIR']:=self[i].Firma;
     zqryMain.Params.ParamValues['PRO']:=self[i].Produkt;
     zqryMain.Params.ParamValues['ANZ']:=self[i].Anzahl;
     zqryMain.params.paramValues['PRE']:=self[i].Preis;
     zqryMain.ExecSQL;
  end;
  begin
    if self[i].ID=-1 then
    begin
      zqryMain.SQL.text:='INSERT INTO WARENVERKAUF1(KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS) VALUES(:KNR, :NAM, :VNA, :FIR, :PRO, :ANZ, :PRE)';
      zqryMain.params.parseSQL(zqryMain.sql.text, True);
      zqryMain.params.ParamValues['KNR']:=self[i].KDNR; //insert
      zqryMain.params.paramValues['NAM']:=self[i].Name;
      zqryMain.params.paramValues['VNA']:=self[i].Vorname;
      zqryMain.params.ParamValues['FIR']:=self[i].Firma;
      zqryMain.Params.ParamValues['PRO']:=self[i].Produkt;
      zqryMain.Params.ParamValues['ANZ']:=self[i].Anzahl;
      zqryMain.params.paramValues['PRE']:=self[i].Preis;
      zqryMain.ExecSQL
    end;

  end;
end;
 finally
    zqryMain.Free;
  end;
end;
Ich habe einen Haltepunt auf zqryMain.Params.ParamValues['CID']:=self[i].ID; //update gesetzt und dann geprüft, wass beim Aufruf des Programms und Hinzufügen eines Datensatzes passiert. Leider nicht dass was ich erwartet habe.
Es ist doch nicht zu glauben, dass das letzte Problem einfach nicht klappen soll.
Ich will eigentlich an dieser Stelle nicht aufgeben, doch ich weiss einfach nicht weiter.
Norbert
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#60

AW: Kundenliste

  Alt 19. Apr 2017, 22:00
Versuch es doch einmal hiermit:
Delphi-Quellcode:
procedure TCustomerList.SavetoDB(con: TZConnection);
var
   zqryMain: TZQuery;
   i: Integer;
begin
  zqryMain:=TZQuery.Create(nil);
  try
    zqryMain.connection:=con;
    for i := 0 to self.Count-1 do
    begin
      if self[i].ID>-1 then
      begin
        zqryMain.SQL.Text:='UPDATE WARENVERKAUF1 SET KDNR=:KNR, NAME =:NAM, VORNAME=:VNA, FIRMA=:FIR, PRODUKT=:PRO, ANZAHL=:ANZ, PREIS=:PRE WHERE ID=:CID';
        zqryMain.params.parseSQL(zqryMain.sql.text, True);
        zqryMain.Params.ParamValues['CID']:=self[i].ID; //update
      end
      else
      begin
        zqryMain.SQL.text:='INSERT INTO WARENVERKAUF1(KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS) VALUES(:KNR, :NAM, :VNA, :FIR, :PRO, :ANZ, :PRE)';
        zqryMain.params.parseSQL(zqryMain.sql.text, True);
      end;
      zqryMain.params.ParamValues['KNR']:=self[i].KDNR;
      zqryMain.params.paramValues['NAM']:=self[i].Name;
      zqryMain.params.paramValues['VNA']:=self[i].Vorname;
      zqryMain.params.ParamValues['FIR']:=self[i].Firma;
      zqryMain.Params.ParamValues['PRO']:=self[i].Produkt;
      zqryMain.Params.ParamValues['ANZ']:=self[i].Anzahl;
      zqryMain.params.paramValues['PRE']:=self[i].Preis;
      zqryMain.ExecSQL;
    end;
  end;
  finally
    zqryMain.Free;
  end;
end;
Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 6 von 10   « Erste     456 78     Letzte »    


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 05:40 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