|
Antwort |
Registriert seit: 1. Mai 2016 Ort: Berlin 419 Beiträge Delphi 10.2 Tokyo Professional |
#41
Das ist der Stand der Dinge:
Delphi-Quellcode:
und das Hauptformular:
unit UCustomerList;
interface uses classes, system.Types, system.SysUtils, ZAbstractRODataset, ZAbstractDataset, ZDataset, ZAbstractConnection, ZConnection ,contnrs, System.Generics.Collections; type TCustomer=class private FID: integer; FKDNR : Integer; FName: string; FVorname: string; FFirma : string; FProdukt: string; FAnzahl : Integer; FPreis : Currency; procedure SetID(const Value: Integer); procedure SetKDNR(const Value: Integer); procedure SetName(const Value: string); procedure SetVorname(const Value: string); procedure SetFirma (const Value : string); procedure SetProdukt(const Value : String); procedure SetAnzahl (const Value : Integer); procedure SetPreis(const Value: Currency); public constructor Create; published property ID: integer read FID write SetID; property KDNR: integer read FKDNr write SetKDNR; property Name: string read FName write SetName; property Vorname: string read FVorname write SetVorname; property Firma: string read FFirma write SetFirma; property Produkt: string read FProdukt write setProdukt; property Anzahl: Integer read FAnzahl write SetAnzahl; property Preis: Currency read FPreis write SetPreis; end; TCustomerList=class(TObjectList<TCustomer>)//generische Liste (contnrs, System.Generics.Collections) procedure LoadFromDB(con: TZConnection); procedure SavetoDB(con: TZConnection); public function AddCustomer(KDNR: integer; Name: string; Vorname: string; Firma: string; Produkt: string; Anzahl: Integer; Preis: Currency):integer; end; implementation { TCustomer } constructor TCustomer.Create; begin inherited; self.FID:=-1; end; procedure TCustomer.SetAnzahl(const Value: Integer); begin FAnzahl := Value; end; procedure TCustomer.SetFirma(const Value: string); begin FFirma := Value; end; procedure TCustomer.SetID(const Value: Integer); begin FID := Value; end; procedure TCustomer.SetKDNR(const Value: Integer); begin FKDNR:= Value; end; procedure TCustomer.SetName(const Value: string); begin FName := Value; end; procedure TCustomer.SetPreis(const Value: Currency); begin FPreis := Value; end; procedure TCustomer.SetProdukt(const Value: String); begin FProdukt := Value; end; procedure TCustomer.SetVorname(const Value: string); begin FVorname := Value; end; { TCustomerList } function TCustomerList.AddCustomer(KDNR: integer; Name, Vorname, Firma, Produkt: string; Anzahl: Integer; Preis: Currency): integer; var Customer: TCustomer; begin Customer:=TCustomer.Create; Customer.KDNR:=KDNR; Customer.Name:=Name; Customer.Vorname:=Vorname; Customer.Firma:=Firma; Customer.Produkt:=Produkt; Customer.Anzahl:=Anzahl; Customer.Preis:=Preis; self.Add(Customer); end; procedure TCustomerList.LoadFromDB(con: TZConnection); var zqyMain: TZQuery; Customer: TCustomer; begin zqyMain:=TZQuery.Create(nil); Try self.Clear; //Dank TObjectlist werden auch alle bereits vorhandenen Objecte automatisch freigegeben zqyMain.connection:=con; zqyMain.sql.text:='SELECT * FROM WARENVERKAUF1'; zqyMain.active:=True; while not zqyMain.eof do begin Customer:=TCustomer.Create; Customer.ID:=zqyMain.FieldByName('ID').AsInteger; // Customer.KDNR:=zqyMain.fieldbyname('KDNR').AsInteger; Customer.Name:=zqyMain.fieldbyname('Name').AsString; Customer.Vorname:=zqyMain.fieldbyname('Vorname').AsString; Customer.Firma:=zqyMain.fieldByName('Firma').AsString; Customer.Produkt:=zqyMain.fieldbyname('Produkt').AsString; Customer.Anzahl:=zqyMain.FieldByName('Anzahl').AsInteger; Customer.Preis:=zqyMain.fieldbyname('Preis').AsCurrency; self.Add(Customer); zqyMain.Next; end; zqyMain.active:=False; Finally zqyMain.free; End; end; 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=:ID' else 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['ID']:=self[i].ID; 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; 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; end.
Delphi-Quellcode:
Ich habe auch das gesamte Programm in der jetzigen Fassung hochgeladen.
//Programm Kundenliste als ersten Versuch eine Objectlist zur Aufnahme der Daten
//für eine SQLite DB einzusetzen. //Hilfe dazu erhielt ich aus vorangegangenen Projekten in der DP vor allem von //Hobbycoder, Haentschmann und P80286, dennen ich hiermit nochmals danke. //Erstellt von EdAdvokat April 2017 unit uMainFRM; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uFRMCustomer, uCustomerList, Vcl.ComCtrls, Data.DB, ZAbstractRODataset, ZAbstractDataset, ZDataset, ZAbstractConnection, ZConnection; type TFRMMainCustomer = class(TForm) lvCustomer: TListView; btnAdd: TButton; btnMake: TButton; btnDelete: TButton; btnAutomatic: TButton; btnClose: TButton; conMain: TZConnection; zqryMain: TZQuery; btnSaveDB: TButton; btnloadDB: TButton; edtKDNR: TEdit; edtName: TEdit; edtVorname: TEdit; edtFirma: TEdit; edtProdukt: TEdit; edtAnzahl: TEdit; edtPreis: TEdit; lblKDNR: TLabel; lblName: TLabel; lblVorname: TLabel; lblFirma: TLabel; lblProdukt: TLabel; lblAnzahl: TLabel; lblPreis: TLabel; edtTestID: TEdit; procedure btnAddClick(Sender: TObject); procedure btnMakeClick(Sender: TObject); procedure btnDeleteClick(Sender: TObject); procedure btnAutomaticClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TOBject); procedure btnCloseClick(Sender: TObject); procedure btnSaveDBClick(Sender: TObject); procedure btnloadDBClick(Sender: TObject); procedure lvCustomerClick(Sender: TObject); private { Private-Deklarationen } CustomerList: TCustomerList; procedure FuelleListView; procedure connect; procedure clearAllFields; procedure saveTableData(ID,KDNR,NAME,VORNAME,FIRMA,PRODUKT,ANZAHL,PREIS:string ); public { Public-Deklarationen } end; var FRMMainCustomer: TFRMMainCustomer; implementation {$R *.dfm} procedure TFRMMainCustomer.btnAutomaticClick(Sender: TObject); var r: integer; I: Integer; KDN, KDN1, Name, Vorname, Firma, Produkt: string; KDNR, Anzahl: Integer; Preis: Currency; begin Customerlist.Clear; Randomize; for I := 0 to 999 do begin r:=Random(10); case r of 0: Name:='Lehmann'; 1: Name:='Krausnig'; 2: Name:='Karlsberg'; 3: Name:='Ludwig'; 4: Name:='Antonia'; 5: Name:='Delphenhorst'; 6: Name:='Erinig'; 7: Name:='Fiedler'; 8: Name:='Gurrlig'; 9: Name:='Henzener'; end; r:=Random(10); case r of 0: Vorname:='Dieter'; 1: Vorname:='Klaus'; 2: Vorname:='Paul'; 3: Vorname:='Helga'; 4: Vorname:='Bernd'; 5: Vorname:='Friedel'; 6: Vorname:='Gustaf'; 7: Vorname:='Heinz'; 8: Vorname:='Joachim'; 9: Vorname:='Manfred'; end; r:=Random(10); case r of 0: KDN:='11'; 1: KDN:='12'; 2: KDN:='13'; 3: KDN:='14'; 4: KDN:='15'; 5: KDN:='16'; 6: KDN:='17'; 7: KDN:='18'; 8: KDN:='19'; 9: KDN:='20'; end; r:=Random(10); case r of 0: KDN1:='21'; 1: KDN1:='22'; 2: KDN1:='23'; 3: KDN1:='24'; 4: KDN1:='25'; 5: KDN1:='26'; 6: KDN1:='27'; 7: KDN1:='28'; 8: KDN1:='29'; 9: KDN1:='30'; end; r:=Random(10); case r of 0: Firma:='Schulbedarf'; 1: Firma:='Schule&mehr'; 2: Firma:='Hausmeisterserv.'; 3: Firma:='Lernen KG'; 4: Firma:='Lehrbuch Co.'; 5: Firma:='Möbel KG'; 6: Firma:='Hefte/Bücher'; 7: Firma:='Buch4you'; 8: Firma:='Lernen4all'; 9: Firma:='Bedarf Schule'; end; r:=Random(10); case r of 0: Produkt:='Stühle'; 1: Produkt:='Tische'; 2: Produkt:='Hefte'; 3: Produkt:='Blöcke'; 4: Produkt:='Bilder'; 5: Produkt:='Kreide'; 6: Produkt:='Bücher'; 7: Produkt:='Tafeln'; 8: Produkt:='Werkzeug'; 9: Produkt:='Mappen'; end; KDNR:=strtoint(KDN[1]+KDN1[1]+format('%.6d',[i])); Anzahl:=Random(20); r:=Random(10000); Preis:=r/100; CustomerList.AddCustomer(KDNR, Name, Vorname, Firma, Produkt, Anzahl, Preis ); end; FuelleListView; end; procedure TFRMMainCustomer.btnCloseClick(Sender: TObject); begin close; end; procedure TFRMMainCustomer.btnAddClick(Sender: TObject); var Customer: TCustomer; begin //Eingabeformular mit Defaultwerten bestücken FRMCustomer.edtKDNR.Text:=''; FRMCustomer.edtName.Text:=''; FRMCustomer.edtName.Text:=''; FRMCustomer.edtVorname.text:=''; FRMCustomer.edtFirma.text:=''; FrmCustomer.edtProdukt.Text:=''; FrmCustomer.edtAnzahl.text:=''; FRMCustomer.edtPreis.text:=''; if frmCustomer.ShowModal=mrOK then begin Customer:=TCustomer.Create; //Das Object Customer erzeugen. Customer.KDNR:=strtoint(frmCustomer.edtKDNR.Text); //Customer wird befüllt Customer.Name:=FRMCustomer.edtName.Text; Customer.Vorname:=FRMCustomer.edtVorname.text; Customer.Firma:=FRMCustomer.edtFirma.text; Customer.Produkt:=FRMCustomer.edtProdukt.text; customer.Anzahl:=strtoint(FRMCustomer.edtAnzahl.text); Customer.Preis:= StrToCurr(FRMCustomer.edtPreis.Text); CustomerList.Add(Customer); //Übergabe an CustomerList FuelleListView; end; end; procedure TFRMMainCustomer.btnDeleteClick(Sender: TObject); begin if lvCustomer.Selected<>nil then begin //Hier löschen wir das Object aus der ObjectListe //Durch die Eigenschaft OwnObjects, die zu jeder TObjectList gehört, //kümmert sich die ObjectListe selber darum, das entsprechende Object Customer //frei zugehen. Brauchen wir also nicht selber mache. //Ansonsten gilt grundsätzlich, was ich selber erzeuge gebe ich auch selber wieder frei CustomerList.Delete(lvCustomer.Selected.Index); FuelleListView; end; end; procedure TFRMMainCustomer.btnloadDBClick(Sender: TObject); begin CustomerList.LoadFromDB(conMain); FuelleListView; end; procedure TFRMMainCustomer.btnSaveDBClick(Sender: TObject); begin CustomerList.SavetoDB(conMain); end; procedure TFRMMainCustomer.btnMakeClick(Sender: TObject); begin if lvCustomer.Selected<>nil then begin //Über den Index kann man nun auf jedes Object in der ObjektListe zugreifen //Damit bestücken wir das Formular mit den Werten aus den Eigenschaften des Objects frmCustomer.edtKDNR.Text:=inttostr(CustomerList[lvCustomer.Selected.Index].KDNR); frmCustomer.edtName.Text:=CustomerList[lvCustomer.Selected.Index].Name; frmCustomer.edtVorname.Text:=CustomerList[lvCustomer.Selected.Index].Vorname; fRMCustomer.edtFirma.Text:=CustomerList[lvCustomer.Selected.Index].Firma; frmCustomer.edtProdukt.text:=CustomerList[lvCustomer.Selected.Index].Produkt; frmCustomer.edtAnzahl.Text:=IntToStr(Customerlist[lvCustomer.Selected.Index].Anzahl); frmCustomer.edtPreis.Text:=CurrToStr(Customerlist[lvCustomer.Selected.Index].Preis); if FRMCustomer.ShowModal=mrOK then begin //Object erzeugen nicht nötig, da es bereits besteht. Zugriff also möglich //für die Übertragung der Daten aus dem Formular CustomerList[lvCustomer.Selected.Index].KDNR:=strtoint(frmCustomer.edtKDNR.Text); CustomerList[lvCustomer.Selected.Index].Name:=frmCustomer.edtName.Text; CustomerList[lvCustomer.Selected.Index].Vorname:=FRMCustomer.edtVorname.Text; CustomerList[lvCustomer.Selected.Index].Firma:=FRMCustomer.edtFirma.text; CustomerList[lvCustomer.Selected.Index].Produkt:=FRMCustomer.edtProdukt.text; CustomerList[lvCustomer.Selected.Index].Anzahl:=strtoint(FRMCustomer.edtAnzahl.text); CustomerList[lvCustomer.Selected.Index].Preis:=strtocurr(FRMCustomer.edtPreis.Text); FuelleListView; end; end; end; procedure TFRMMainCustomer.clearAllFields; begin with FRMMainCustomer do begin edtKDNR.Clear; edtName.Clear; edtVorname.Clear; edtFirma.Clear; edtProdukt.Clear; edtAnzahl.Clear; edtPreis.Clear; end; end; procedure TFRMMainCustomer.connect; begin conMain.LibraryLocation:=ExtractFilePath(application.ExeName)+'sqlite3.dll'; conMain.Database:=ExtractFilePath(application.ExeName)+'WarenVK.sqlite'; conMain.Connected:=true; zqryMain.SQL.Clear; zqryMain.Params.Clear; zqryMain.SQL.Text:='SELECT * FROM WARENVERKAUF1'; zqryMain.Open; while not zqryMain.Eof do begin saveTableData(zqryMain.FieldByName('ID').AsString,zqryMain.FieldByName('KDNR').AsString,zqryMain.FieldByName('Name').AsString, zqryMain.FieldByName('Vorname').AsString,zqryMain.FieldByName('Firma').AsString,zqryMain.FieldByName('Produkt').AsString,zqryMain.FieldByName('Anzahl').AsString, zqryMain.FieldByName('Preis').AsString); zqryMain.Next end; zqryMain.Close; end; procedure TFRMMainCustomer.FormCreate(Sender: TObject); begin CustomerList:=TCustomerList.Create; connect; clearAllFields; end; procedure TFRMMainCustomer.FormDestroy(Sender: TOBject); begin CustomerList.Free; end; procedure TFRMMainCustomer.FuelleListView; var li: TListItem; I: Integer; begin lvCustomer.Items.BeginUpdate; Try //ListView mit Daten aus der ObjectList befüllen. lvCustomer.Items.Clear; for I := 0 to CustomerList.Count-1 do begin li:=lvCustomer.Items.Add; li.Caption:=inttostr(CustomerList[i].ID); // li.SubItems.Add(inttostr(CustomerList[i].KDNR)); // li.SubItems.Add(CustomerList[i].Name); li.SubItems.Add(CustomerList[i].Vorname); li.SubItems.Add(CustomerList[i].Firma); li.SubItems.Add(CustomerList[i].Produkt); li.SubItems.Add(inttostr(CustomerList[i].Anzahl)); li.SubItems.Add(FormatCurr('#0.00 €', CustomerList[i].Preis)); end; Finally lvCustomer.Items.EndUpdate; End; end; procedure TFRMMainCustomer.lvCustomerClick(Sender: TObject); var CurrentCustomerID : string; begin if lvCustomer.SelCount>=1 then begin CurrentCustomerID:=lvCustomer.Selected.Caption; // zqryMain.SQL.Clear; zqryMain.Params.Clear; zqryMain.SQL.Text:='SELECT * FROM WARENVERKAUF1 WHERE ID = :CID'; zqryMain.ParamByName('CID').AsString := CurrentCustomerID; // zqryMain.Open; edtKDNR.text:=zqryMain.FieldByName('KDNR').AsString; edtName.text:=zqryMain.FieldByName('Name').AsString; edtVorname.Text:=zqryMain.FieldByName('Vorname').AsString; edtFirma.text:=zqryMain.FieldByName('Firma').asstring; edtProdukt.text:=zqryMain.FieldByName('Produkt').AsString; edtAnzahl.text:=zqryMain.FieldByName('Anzahl').AsString; edtPreis.Text:=zqryMain.FieldByName('Preis').AsString; zqryMain.Next; // zqryMain.close; end; end; procedure TFRMMainCustomer.saveTableData(ID, KDNR, NAME, VORNAME, FIRMA, PRODUKT, ANZAHL, PREIS: string); var item:TListItem; begin Item:=lvCustomer.Items.Add; item.Caption:=ID; item.SubItems.Add(KDNR); // item.SubItems.Add(Name); item.SubItems.Add(Vorname); item.SubItems.Add(Firma); item.SubItems.Add(Produkt); item.SubItems.Add(Anzahl); item.SubItems.Add(Preis); end; end. Mein Debuggerversuch hat ergeben, dass vermutlich in der WiniNet.dll eine Kollision mit meinem Programm auftritt. Es ist die procedure TListHelper.Check.InsertRange, die dazu führt, dass die Meldung "Argument außerhalb des Bereiches" auftritt. Dies geschieht, wenn ich nach Programmaufruf versuche einen Datensatz zu löschen oder ihn zu bearbeiten. Rufe ich loadfromDB auf kann ich einen Datensatz bearbeiten und löschen. Auch die Verschieberei nach links in der Anzeige ist in diesem Fall nicht mehr aufgetreten. Blöd ist jetzt nur, dass beim Aufruf von SaveToDB ein Rödeln einsetzt und sich das Programm festfährt d.h. es dauert etwa 3 Minuten bis der Speicherungsprozess beendet ist. Ob die Methode SaveToDB wirklich so ok ist, oder sind da andere Unstimmigkeiten im Wege? Noch ein Wort zu Ralf: Danke für Deine Hinweise. Die werde ich in Ruhe ansehen, doch habe Verständnis dafür, dass ich auf diesem Gebiet so etwas von neu und unbeleckt bin, dass ich mich erst einmal darauf konzentrieren möchte, das das ganze zum vernünftigen Laufen kommt. Vermutlich habe ich an zu vielen Stellschrauben gedreht, dass nun das Speichern in die DB wieder Probleme macht. Den Debuggerversuch habe ich so durchgeführt, dass ich einen Haltepunkt gesetzt habe und dann die entsprechenden Handlungen im Programm selbst ausgeführt habe um dann mit F7 Schritt für Schritt weiter zu gehen. Da kam ich an dem o.g. Punkt an. Was ich daraus ableiten muss, weis ich leider nicht.
Norbert
|
Zitat |
Registriert seit: 22. Feb 2017 955 Beiträge |
#42
Die Sache ist auch ganz einfach.
In der procedure connect öffnest du deine Datenbank und machst das Select über die Tabelle. Dort rufst du auch die Methode saveTableData auf, die wiederum die Daten auf deinem Listview ausgibt. Fertig. Wenn du dann über den Button Bearbeiten ein Item der ObjectList holen willst, geht das nicht, weil du da auch nie was reingeschrieben hat. Die ist nämlich leer. Die Vorgehensweise ist auch nicht so schlau. Besser wäre es (ich glaube so hatte ich es dir auch gezeigt) die Daten erst mal nur in die ObjectList einzulesen. Die entsprechende Methode "AddCustomer" gibt es in der CustomerList ja schon. Und wenn dann das Query abgearbeitet ist, also nach dem zqryMain.Close, dann mit FuelleListView den Inhalt der CustomerList in die Listview schreiben zu lassen. Und die Krönung wäre es noch, wenn die die Query-Abfrage noch in eine Methode der CustomerList übernimmst und die Objecte auch dort anlegen lässt. Die Connection könntest du als Parameter der Methode übergeben. Gruß Hobbycoder [Edit]: Grad gesehen, die Laderoutine gibt es in der CustomerList ja auch schon. Sie heißt LoadFromDB(...); Schaut die mal in der Mainform die proceudre btnloadDBClick an. Dort machst du es richtig. Und wenn man auf den Button "DB laden" klickt kann man auch editieren, weil dann die Customerlist auch Daten hat. Schmeiß das ganze Query mal aus der OnCreate raus und füge statt dessen mal btnloadDBClick(self) ein. Voila...dann geht's. In den Proceduren der Buttons Bearbeiten, Neu, löschen ... machst du es ja richtig. Und dadurch, dass du im OnCreate nur die Listview bestückt hast, hast du nicht mehr gemerkt, dass die ObjectList nicht geladen wurde. Fehler die mach zu Anfang gerne macht. Mit der Zeit kommt die Erfahrung und solche Fehler passieren dir nicht mehr. Im Übrigen, lass dich durch die vielen (richtigen) Hinweise nicht entmutigen. Sie sind gut gemeint. Ich würde dir aber raten erst einmal bei deinem jetzigen Code zu bleiben. Sicherlich kann man das anders auch noch schöner und besser machen. Aber wenn du jetzt anfängst alles immer wieder umzubauen, dann verwirrt dich das mehr, als alles andere. Besser, sein Ziel erst mal, wenn auch unschön, zu erreichen. Wenn es dann erst mal soweit läuft, dann entweder langsam umbauen, oder noch besser, mit dem hinzugewonnenen Wissen und der Erfahrung noch mal ganz neu aufbauen. Meine ersten Gehversuche in Delphi vor 20 Jahren sahen noch viel schlimmer aus. Geändert von Hobbycoder (18. Apr 2017 um 14:30 Uhr) |
Zitat |
Registriert seit: 9. Dez 2010 Ort: Mönchengladbach 1.736 Beiträge Delphi 6 Enterprise |
#43
Bei Start des Programmes füllst du in der Connect-Funktion über SaveTableData die ListView.
Die CustomerList ist aber noch leer. Somit funktionieren die Delete und Make funktionen nicht. (Edit: also im Prinzip das, was Hobbycode auch sagt). Folgende Änderung reicht aber schon:
Delphi-Quellcode:
procedure TFRMMainCustomer.connect;
begin conMain.LibraryLocation:=ExtractFilePath(application.ExeName)+'sqlite3.dll'; conMain.Database:=ExtractFilePath(application.ExeName)+'WarenVK.sqlite'; conMain.Connected:=true; //neu CustomerList.LoadFromDB(conMain); FuelleListView; //alt kann weg, die ganze Fkt. SaveTableData kann mMn weg //zqryMain.SQL.Clear; //zqryMain.Params.Clear; //zqryMain.SQL.Text:='SELECT * FROM WARENVERKAUF1'; //zqryMain.Open; //while not zqryMain.Eof do //begin //saveTableData(zqryMain.FieldByName('ID').AsString, // zqryMain.FieldByName('KDNR').AsString, // zqryMain.FieldByName('Name').AsString, // zqryMain.FieldByName('Vorname').AsString, // zqryMain.FieldByName('Firma').AsString, // zqryMain.FieldByName('Produkt').AsString, // zqryMain.FieldByName('Anzahl').AsString, zqryMain.FieldByName('Preis').AsString); //zqryMain.Next //end; //zqryMain.Close; end;
Ralph
|
Zitat |
Registriert seit: 9. Dez 2010 Ort: Mönchengladbach 1.736 Beiträge Delphi 6 Enterprise |
#44
Wenn es damit dann erstmal läuft musst du noch folgendes bedenken:
Löchst du einen Eintrag und er wird aus der ListView und der CustomerList auch entfernt, bleibt der aber weiterhin in der DB gespeichert, d.h. bei nächsten Aufruf des Programmes mit allen Daten aus der DB, ist er wieder da. Du musst daher in deiner CustomerList auch die Funktion Delete der ObjektList überschreiben, damit an der Stelle der entsprechende Datensatz zusätzlich auch aus der DB gelöscht wird.
Ralph
|
Zitat |
Registriert seit: 22. Feb 2017 955 Beiträge |
#45
Wenn es damit dann erstmal läuft musst du noch folgendes bedenken:
Löchst du einen Eintrag und er wird aus der ListView und der CustomerList auch entfernt, bleibt der aber weiterhin in der DB gespeichert, d.h. bei nächsten Aufruf des Programmes mit allen Daten aus der DB, ist er wieder da. Du musst daher in deiner CustomerList auch die Funktion Delete der ObjektList überschreiben, damit an der Stelle der entsprechende Datensatz zusätzlich auch aus der DB gelöscht wird. Wenn er es so lässt, wie es jetzt ist, könnte er zumindest ein versehentliches Löschen durch "DB laden" schnell wieder rückgängig machen. Ansonsten könnte man das so machen. |
Zitat |
Registriert seit: 9. Dez 2010 Ort: Mönchengladbach 1.736 Beiträge Delphi 6 Enterprise |
#46
Wenn es damit dann erstmal läuft musst du noch folgendes bedenken:
Löchst du einen Eintrag und er wird aus der ListView und der CustomerList auch entfernt, bleibt der aber weiterhin in der DB gespeichert, d.h. bei nächsten Aufruf des Programmes mit allen Daten aus der DB, ist er wieder da. Du musst daher in deiner CustomerList auch die Funktion Delete der ObjektList überschreiben, damit an der Stelle der entsprechende Datensatz zusätzlich auch aus der DB gelöscht wird. Wenn er es so lässt, wie es jetzt ist, könnte er zumindest ein versehentliches Löschen durch "DB laden" schnell wieder rückgängig machen. Ansonsten könnte man das so machen.
Ralph
|
Zitat |
Registriert seit: 28. Apr 2008 Ort: Stolberg (Rhl) 6.659 Beiträge FreePascal / Lazarus |
#47
"könnte.."
Darum insistiere ich ja so auf eine Struktur. Wenn ein Datensatz gelöscht werden soll, dann[LIST=1] [/[*]soll er nicht mehr für die Anzeige zur Verfügung stehen[*]soll er sofort aus der Datenbank gelöscht werden LIST] oder[LIST=1] [/[*]soll er nicht mehr führ die Anzeige zur Verfügung stehen[*]soll er als zu löschen markiert werden und irgendwann in der DB gelöscht werden LIST] oder [LIST=1] [/[*]steht er als "Prototyp" in der Anzeige zur Verfügung[*]wird er sofort in der DB gelöscht LIST] und noch weiter Möglichkeiten .... Für den Anfang sollte man sich für eine Kombination entscheiden, und die dann konsequent durchziehen. Falls sich herausstellen sollte, das das Murks ist, dann dreht man an den entsprechenden Schrauben und gut ist. Gruß K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector |
Zitat |
Registriert seit: 1. Mai 2016 Ort: Berlin 419 Beiträge Delphi 10.2 Tokyo Professional |
#48
vielen Dank erst einmal. Die connect-procedure sieht nun ganz kurz so aus:
Delphi-Quellcode:
Somit kann ich Hinzufügen bearbeiten und löschen. Nur das Problem mit dem Speichern besteht noch. Er speichert und speichert ohne Ende. Das ging doch zuvor. Da muss doch eine Endlosschleife aufgerufen worden sein.? Wenn das noch klappt glaube ich wäre ich am Ziel.
procedure TFRMMainCustomer.connect;
begin conMain.LibraryLocation:=ExtractFilePath(application.ExeName)+'sqlite3.dll'; conMain.Database:=ExtractFilePath(application.ExeName)+'WarenVK.sqlite'; conMain.Connected:=true; btnloadDBClick(self); end;
Norbert
|
Zitat |
Registriert seit: 1. Mai 2016 Ort: Berlin 419 Beiträge Delphi 10.2 Tokyo Professional |
#49
Habe mir nun die procedure SaveToDB vorgenommen. Wenn ich sie aufrufe speichert er unendlich lange und die Datenbank wird immer größer. Er addiert vermutlich die besthenden Datensätze bis ich das Programm gewaltsam abbreche. Habe dann gesondert nur Insert mit den entsprechenden Werten aufgerufen, mit dem gleichen Ergebnis. Zwischenzeitlich wieder eine frühere Version der DB eingespielt mit weniger Datensätzen. Auch wenn ich nur mit Update arbeite das gleiche Ergebnis, jedoch wird der neu erstellte Datensatz nicht gespeichert.
Die for i:=0 to self.count-1 do Schleife ist doch notwenig. Er holt sich doch damit die Daten aus der Objectlist und speichert sie in der Datenbank - oder? Er sollte doch bei self.count-1 aufhören. Mit dem Versuch den Debugger anzuwerfen bin ich gescheitert. Habe auf den Beginn der Procedure SaveToDB einen Haltepunkt gesetzt und dann den Button gedrückt und das Drama nahm seinen Lauf. Er speichert und speichert bis ich ihn abwürge.Natürlich kein Ergebnis dieses Versuches. Aber vielleicht mache ich das auch falsch. Jedenfalls glaube ich noch immer dass es doch klappen sollte. Ich sehe jedoch keine weiteren Stellschrauben in diesr procedure, nachdem ich alles schon gesondert probiert habe. Ist die Procedure wirklich richtig? Zwischenzeitlich habe ich mir den Programmablauf auf Zettel kommentiert, um genau nachzuvollziehen was wann passiert. Leider noch nicht abschließend.
Norbert
|
Zitat |
Registriert seit: 22. Feb 2017 955 Beiträge |
#50
also das speichern geht bei mir wunderbar. Wenn gleich es auch sehr lange dauert.
Generell ist es natürlich besser, die veränderten Daten gleich zu speichern. Du brauchst lediglich zu dem Object TCustomer zwei Methoden zum Speichern und zum Löschen hinzufügen. Beim Speichern wieder die ID rüfen, wenn =-1 dann insert sonst update. Und in der Mainform rufst du die dann bei den Buttons passen auf. Wenn du aber bei deiner bisherigen Form bleiben willst, dann setzt die bei gelöschten Datensätzen die ID einfach auf -2. dann kannst du in der SaveToDB auf id=-2 prüfen und statt insert bzw. update machst du dir noch einen Remove-Statement dazu. Allerdings müsstest du dann dort auch das dazugehörige Object löschen, damit du hinterher auch mit FuelleListView die Anzeige neu aufbauen kannst. Und du müsstest in der SaveToDB entweder for i:=self.count-1 downto 0 machen, oder alle Object die ID=-2 habe erst nach dem Speichern und vor dem FuelleListview löschen. Klinkt umständlich...ist es auch. Besser wie oben und gleich speichern, löschen und hinzufügen, und danach immer FuelleListView. Das hätte auch den Vorteil, dass dein Programm auch mit mehreren Clients funktionieren könnte. Denn zur Zeit würde ein Speichern der DB immer die Änderungen überschreiben, die ein anderer User eventuell gerade gespeichert hat, oder sogar zu Datenverlust führen. Stell dir mal vor, du und ein anderer User laden die DB an 2 Rechnern. Jetzt löscht der andere einen Datensatz und speichert. Anschließend änderst du den gleichen Datensatz. bei dir ist ja noch in der CustomerList vorhanden. Anschließend willst du speichern. Dein SQL-Statement UPDATE kann diesen Datensatz aber nicht finden (where ID=:id) und speichert ihn dem zur Folge auch nicht. Weg isser. Und so ließen sich noch weitere Szenarien darstellen. Geändert von Hobbycoder (18. Apr 2017 um 19:49 Uhr) |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |