[Erledigt] Noch eine Frage zu OOP Klassen mit Objektlisten

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

[Erledigt] Noch eine Frage zu OOP Klassen mit Objektlisten

Beitragvon MacWomble » 8. Okt 2019, 14:53 [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlisten

Ich habe einige Klassen, welche wiederum Objektlisten anderer Klassen beinhalten. Dies funktioniert so weit ganz gut. Jedoch habe ich Probleme beim Speichern in die Datenbank, wenn dies zu verschachtelt wird.

Adresse(Objekt) enthält Kontaktdaten (Objektliste) und Kontakte (Objektliste) das funktioniert so weit.

Kontaktnr:=Adresse.Kontaktdaten.Items[i] //Telefonnummern für Adresse
Kontakt:=Adresse.Kontakte.Items[i] // Ansprechpartner
Kontaktnr:=Kontakt.Kontaktdaten.Items[x] //Telefonnummern für Ansprechpartner

funktioniert alles, nur an der einen Stelle nicht.

Kontakt(Objekt aus Kontakte) enthält Kontaktdaten (Objektliste) das funktioniert in den Fenstern (Anzeige) einwandfrei, jedoch komme ich in der Speichern-Funktion nicht an die Kontaktdaten:

Code: Alles auswählen
 
  TKontakt = class(TObject)
  private   
...
    fKontaktdaten: TKontaktdatenListe;   
  published
...
    property Kontaktdaten: TKontaktdatenListe read fKontaktdaten write fKontaktdaten;
...
 
//Kontakt.Kontaktdaten:= TKontaktdatenliste.Create;  wird an anderer Stelle ausgeführt und es können Daten darin erzeugt und gelesen werden
 
procedure TKontaktListe.WriteListData(IDAdresse: integer);
var
  LastID: integer;
  i: integer;
  cnt: integer;
begin
  debugln('TKontaktListe.WriteListData');
  LastID := 0;
  with dtmBasis.qrySQL do
  begin
    for i := 0 to Self.Count - 1 do                // Link zur Adresse setzen !
    begin                                 
      Self.Items[i].SetIDAdresse(IDAdresse);
    end;
    for i := 0 to Self.Count - 1 do
    begin
      if Self.Items[i].fIsChanged then
      begin
        Self.Items[i].fIsChanged := False;
        if Self.Items[i].fID = 0 then
        begin {Insert}
          DebugLn('  Datensatz wird neu angelegt');
          SQL.Clear;
          SQL.Add('Insert Into Kontakte');
          SQL.Add('(fk_adresse, kon_anrede, kon_titel, kon_vorname, kon_zuname, kon_abteilung, kon_funktion, kon_briefanrede, kon_notiz) ');
          SQL.ADD('VALUES');
          SQL.ADD('(:fk_adresse, :kon_anrede, :kon_titel, :kon_vorname, :kon_zuname, :kon_abteilung, :kon_funktion, :kon_briefanrede, :kon_notiz) ');
          Prepare;
        end
        else
        begin  //Update
          DebugLn('  Datensatz ' + IntToStr(Self.Items[i].fid) + ' wird aktualisiert');
          SQL.Clear;
          SQL.ADD('UPDATE Kontakte SET');
          SQL.ADD('fk_adresse = :fk_adresse,');
 
          SQL.ADD('kon_anrede = :kon_anrede,');
...
          SQL.ADD('WHERE idkontakt = :idkontakt;');
          Params.ParamByName('idkontakt').AsInteger := Self.Items[i].fID;
        end;
 
        Params.ParamByName('fk_adresse').AsInteger := Self.Items[i].fIDAdresse;
...
        Params.ParamByName('kon_notiz').AsString := Self.Items[i].fNotiz;
        try
          ExecSQL;
          DebugLn('    Gespeichert !');
        except
          On E: Exception do
            debugln(' ' + E.Message);
        end;
      end
      else
        DebugLn('  Datensatz ' + IntToStr(Self.Items[i].fID) + ' ist aktuell');
      if LastID = 0 then
        LastID := Self.Items[i].fID;
// Bis hier funktionier es
 
// HIER IST DAS PROBLEM (so funktioniert das allerdings bei den Adressen problemlos):
// fKontaktdaten wird richtigerweise als TKontaktDatenliste erkannt!
// Self.Items[i].fKontaktdaten oder Self.Items[i].Kontaktdaten ist hier aber nicht ansprechbar bzw. führt zu einem 'Hänger' ohne weiter Fehlerangabe
//
       if assigned(Self.Items[i].fKontaktdaten) then // wird noch ausgeführt
           Self.Items[i].fKontaktdaten.WriteListData(Self.Items[i].IDAdresse, LastID); //bleibt hängen, Fehler definitiv NICHT in Kontaktdaten.WriteListData, das wird schon nicht mehr aufgerufen!
    end; //for i
  end;
end;               
 
Zuletzt geändert von MacWomble am 9. Okt 2019, 15:20, insgesamt 5-mal geändert.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon fliegermichl » 8. Okt 2019, 15:11 Re: Noch eine Frage zu OOP Klassen mit Objaktlisten

Also zum einen kannst du bei self.irgendwas das self. weglassen.

MacWomble hat geschrieben:// HIER IST DAS PROBLEM (so funktioniert das allerdings bei den Adressen problemlos):
// fKontaktdaten wird richtigerweise als TKontaktDatenliste erkannt!
// Self.Items[i].fKontaktdaten oder Self.Items[i].Kontaktdaten ist hier aber nicht ansprechbar bzw. führt zu einem 'Hänger' ohne weiter Fehlerangabe
//
if assigned(Self.Items[i].fKontaktdaten) then // wird noch ausgeführt
Self.Items[i].fKontaktdaten.WriteListData(Self.Items[i].IDAdresse, LastID); //bleibt hängen, Fehler definitiv NICHT in Kontaktdaten.WriteListData, das wird schon nicht mehr aufgerufen!


Ich vermute, daß du umgekehrt darauf zugreifen musst.
Also statt self.Items[i].fKontaktdaten
Kontaktdaten.Items[i].WriteListData...
fliegermichl
Lazarusforum e. V.
 
Beiträge: 395
Registriert: 9. Jun 2011, 09:42

Beitragvon fliegermichl » 8. Okt 2019, 15:21 Re: Noch eine Frage zu OOP Klassen mit Objaktlisten

Übrigens kannst Du Items als default property definieren, dann verkürzt sich das auf
Code: Alles auswählen
 
 Kontaktdaten[i].Write...
 
Definiert wird das so:
interface
uses contnrs;
 
type
TKontaktdaten = class ( TObjectList )
 function Get(Index : integer) : TKontakt;
 procedure Put(Index : integer; Item : TKontakt);
 property Items[index : integer] : TKontakt read get write put; default;
end;
 
implementation
 
function TKontaktdaten.Get(Index : integer) : TKontakt;
begin
 Result := TKontakt(inherited Get(Index));
end;
 
procedure TKontaktdaten.Put(Index : integer; Item : TKontakt);
begin
 inherited Put(Index, Kontakt);
end;
 
fliegermichl
Lazarusforum e. V.
 
Beiträge: 395
Registriert: 9. Jun 2011, 09:42

Beitragvon MacWomble » 8. Okt 2019, 15:29 Re: Noch eine Frage zu OOP Klassen mit Objaktlisten

fliegermichl hat geschrieben:Also zum einen kannst du bei self.irgendwas das self. weglassen.

MacWomble hat geschrieben:// HIER IST DAS PROBLEM (so funktioniert das allerdings bei den Adressen problemlos):
// fKontaktdaten wird richtigerweise als TKontaktDatenliste erkannt!
// Self.Items[i].fKontaktdaten oder Self.Items[i].Kontaktdaten ist hier aber nicht ansprechbar bzw. führt zu einem 'Hänger' ohne weiter Fehlerangabe
//
if assigned(Self.Items[i].fKontaktdaten) then // wird noch ausgeführt
Self.Items[i].fKontaktdaten.WriteListData(Self.Items[i].IDAdresse, LastID); //bleibt hängen, Fehler definitiv NICHT in Kontaktdaten.WriteListData, das wird schon nicht mehr aufgerufen!


Ich vermute, daß du umgekehrt darauf zugreifen musst.
Also statt self.Items[i].fKontaktdaten
Kontaktdaten.Items[i].WriteListData...


Nein, in WriteListData werden die Items in einer Schleife abgearbeitet.
Rein Gedanklich ist es schon richtig, wie ich das da habe. Bei Adresse.Kontaktdaten geht es so ja auch nur bei Kontakte.Items[i].Kontaktdaten nicht, was ja im Prinzip analog zu Kontakt.Kontaktdaten steht. Aber ich möchte es hier in einer Schleife aller Kontakte abarbeiten.
(Vermutlich auch nicht bei Adressen.Items[]i.Kontaktdaten)
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon MacWomble » 8. Okt 2019, 23:04 Re: [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlist

:oops: Habs gefunden. Ich habe die Kontaktdaten zu einem falschen Zeitpunkt frei gegeben!

Das mit den Items als Default Property muss ich mir noch genauer ansehen, aber ich glaube das bringt mit keine wesentlichen Vorteile.

Danke jedenfalls für Eure Bemühungen und Tipps!
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon fliegermichl » 9. Okt 2019, 08:38 Re: [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlist

MacWomble hat geschrieben:Das mit den Items als Default Property muss ich mir noch genauer ansehen, aber ich glaube das bringt mit keine wesentlichen Vorteile.


Der Vorteil ist, daß du nicht bei jedem Zugriff einen Typecast machen musst. Die Property Items von TObjectList sind vom Typ TObject. Wenn Items eine Liste von speziellen Klasseninstanzen hält, musst du ansonsten bei jedem Zugriff
Code: Alles auswählen
 
TMyClass(Items[i]).MyProperty := irgendwas;
 


schreiben.
fliegermichl
Lazarusforum e. V.
 
Beiträge: 395
Registriert: 9. Jun 2011, 09:42

Beitragvon MacWomble » 9. Okt 2019, 12:18 Re: [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlist

fliegermichl hat geschrieben:
MacWomble hat geschrieben:Das mit den Items als Default Property muss ich mir noch genauer ansehen, aber ich glaube das bringt mit keine wesentlichen Vorteile.


Der Vorteil ist, daß du nicht bei jedem Zugriff einen Typecast machen musst. Die Property Items von TObjectList sind vom Typ TObject. Wenn Items eine Liste von speziellen Klasseninstanzen hält, musst du ansonsten bei jedem Zugriff
Code: Alles auswählen
 
TMyClass(Items[i]).MyProperty := irgendwas;
 


schreiben.


Danke, ich habe das schon verstanden. Zunächst quäle ich mich noch mit anderen Grundlagen :shock:
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon MacWomble » 9. Okt 2019, 12:22 Re: Noch eine Frage zu OOP Klassen mit Objektlisten

... hab den Thread nochmal aktiviert:

Ich habe ja die Klasse TAdresse, welche Kontakte (TObjectlist) und Kontaktnummern (TObjectlist) enthält.
Diese Listen sollen mit der Adressinstanz erzeugt und zerstört werden. Hierzu habe ich folgenden Konstrukt, welcher aber
beim Aufruf von 'Adresse.free' in einem Assemblerfehler endet.
Wo habe ich mich diesmal geirrt? :oops: (möglich ist auch, dass ich den :evil: wieder ganz wo anders implementiert habe )

Code: Alles auswählen
{ TAdresse }
 
  TAdresse = class(TObject) 
 
private
  fKontaktnummern: TKontaktdatenListe;
  fKontakte: TKontaktListe; 
  ...
 
public
  constructor Create;
  destructor Destroy; override;
  property Kontaktnummern: TKontaktdatenListe read fKontaktnummern write fKontaktnummern;
  property Kontakte: TKontaktListe read fKontakte write fKontakte;
  ...
 
 
constructor TAdresse.Create;
begin
  Inherited create;
  fKontakte:=TKontaktListe.Create();
  fKontaktnummern:= TKontaktdatenListe.Create();
end;
 
destructor TAdresse.Destroy;
begin
  if assigned(fKontakte) then FreeAndNil(fKontakte);
  if assigned(fKontaktnummern) then FreeAndNil(fKontaktnummern);
  Inherited Destroy;
end;     
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon fliegermichl » 9. Okt 2019, 12:41 Re: Noch eine Frage zu OOP Klassen mit Objektlisten

Genauso ist es richtig. Der Fehler liegt definitiv woanders.
Setz mal einen Breakpoint in TKontaktdatenliste.Destroy. Vielleicht bringt das mehr Klarheit.
fliegermichl
Lazarusforum e. V.
 
Beiträge: 395
Registriert: 9. Jun 2011, 09:42

Beitragvon MacWomble » 9. Okt 2019, 15:19 Re: Noch eine Frage zu OOP Klassen mit Objektlisten

Nochmals Danke. Es hat weiter geholfen, zu wissen, dass der Fehler nicht hier steckte.

Ursache waren vergessene Freigaben (also zu viele davon ;-) )
Das hängt damit zusammen, dass ich die Struktur veränderte.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon Warf » 9. Okt 2019, 18:18 Re: [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlist

Übrigens der FPC kann valgrind code erzeugen. Valgrind ist ein mittelprächtiger Simulator (d.h. es ist nicht das schnellste) das alle Speicherzugriffe trackt. d.h. Wenn du ein Use after Free hast, Free vergisst, out of bounds array zugriff, oder sonstige Speicherfehler hast, wird valgrind dir das sagen, mit genauem Code angabe (z.B. bei Use after Free wird dir Valgrind sagen wo du es zunächst gefreed hast und wo es dann tatsächlich kracht).

Außerdem:
Code: Alles auswählen
  if assigned(fKontakte) then FreeAndNil(fKontakte);
  if assigned(fKontaktnummern) then FreeAndNil(fKontaktnummern);


Assigned ist in etwa sowas:
Code: Alles auswählen
function Assigned(p: Pointer): Boolean;
begin
  Result := p <> nil;
end;

FreeAndNil ist das:
Code: Alles auswählen
 
procedure FreeAndNil(var obj);
begin
  TObject(obj).free;
  pointer(obj):=nil;
end;

Und TObject.Free ist das
Code: Alles auswählen
procedure TObject.Free;
begin
  if self <> nil then self.destroy;
end;

Wenn wir das alles einmal inlinen steht da also in deinem konstruktor:
Code: Alles auswählen
if fKontakte <> nil then
begin
  if fKontakte <> nil then
    fKontakte.Destroy;
  fKontakte := nil;
end;

Zum einen ist das if assigned also völlig überflüssig, zum anderen musst du nicht FreeAndNil benutzen, denn das ist der Destruktor. Danach exsistieren die Felder eh nicht mehr. FreeAndNil muss man nur benutzen wenn man danach noch zugriff auf das Feld hat, damit man nicht versehentlich auf die alte Addresse schreibt.
Nimm doch also einfach die deutlich kürzere variante:
Code: Alles auswählen
  fKontakte.Free;
  fKontaktnummern.Free;

Hast keinen nachteil dardurch, außer das dein Code leserlicher wird
Warf
 
Beiträge: 1215
Registriert: 23. Sep 2014, 17:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon MacWomble » 9. Okt 2019, 20:55 Re: [Erledigt] Noch eine Frage zu OOP Klassen mit Objektlist

Danke! :D
Muss ja nicht alles doppelt gemoppelt werden ... :oops:
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
Lazarusforum e. V.
 
Beiträge: 851
Registriert: 17. Apr 2008, 01:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19.1 Cinnamon / CodeTyphon LAB Version 6.90 / FP 3.3.1 Rev 42237 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

• Themenende •

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste

porpoises-institution
accuracy-worried