AGB  ·  Datenschutz  ·  Impressum  







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

Getter wird übergangen

Ein Thema von Medium · begonnen am 17. Jun 2010 · letzter Beitrag vom 18. Jun 2010
Antwort Antwort
Seite 1 von 2  1 2      
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#1

Getter wird übergangen

  Alt 17. Jun 2010, 18:07
Ahoi!

Ich habe hier folgende Struktur (eine Objekt-Relationale Abbildung zu einer DB, Delphi 2010):
Delphi-Quellcode:
  TDB = class
  private
    type
      TDBUser = class
      private
        class var FID: Integer;
        class function GetName: string; static;
        class procedure SetName(const Value: string); static;
        // für jedes DB feld eben...
      public
        class property ID: Integer read FID;
        class property Name: string read GetName write SetName;
      end;
    class var FQuery: TUniQuery;
    class var FUser: TDBUser;
    class function GetDBUserByLogin(aLogin: string): TDBUser; static;
  public
    class property UsersByLogin[aLogin: string]: TDBUser read GetDBUserByLogin;
  end;

implementation

class function TDB.GetDBUserByLogin(aLogin: string): TDBUser;
begin
  Query.SQL.Text := 'SELECT id FROM users WHERE login=:lg';
  Query.ParamByName('lg').AsString := aLogin;
  Query.Open;
  if Query.RecordCount=0 then
  begin
    Query.Close;
    raise EUserDoesNotExistException.Create();
  end;
  FUser.FID := Query.FieldByName('id').AsInteger;
  result := FUser;
  Query.Close;
end;
Um die ID eines Users anhand seines Logins zu erhalten, tue ich in einer anderen Unit dies:
Delphi-Quellcode:
constructor TUser.Create(aLogin, aPassword: string);
var
  id: Integer;
begin
  if FInstanceCounter > 0 then
    raise Exception.Create('Es ist bereits ein User angemeldet. Melden Sie diesen ab, bevor Sie sich einloggen.');

  try
    id := TDB.UsersByLogin[aLogin].ID; // !!! Hier wichtig !!! :)
  except
    raise Exception.Create('Benutzer '''+aLogin+''' existiert nicht.');
  end;

  if TDB.Users[id].Password <> aPassword then
    raise Exception.Create('Ungültiges Passwort für Benutzer '''+aLogin+'''.');

  FId := id;
  FLogin := aLogin;
  FName := TDB.Users[id].Name;
  FSurname := TDB.Users[id].Surname;
  FRights := TDB.Users[id].Rights;

  inc(FInstanceCounter);
end;
An der markierten Stelle passiert es dann: NICHTS!
Es wird niemals die Methode GetDBUserByLogin() durchlaufen, und "id" hat nachher immer den Wert "0" (diese ID gibt es nicht in der DB). Ich erhalte keine Hinweise/Warnungen vom Compiler, kann einen Haltepunkt auf die oben markierte Zeile setzen, ein solcher wird in der Methode GetDBUserByLogin() jedoch deaktiviert. (Das ist die einzige Überladung davon.)
Löschen der DCUs hat leider nichts gebracht, sowie auch das testweise entfernen des try-Blocks. Auch die Optimierung abzuschalten hat an diesem Verhalten nichts geändert.

Bin es nun ich, der einen Denkfehler hat und ihn nicht findet, oder wäre das es wert dem Support vorzutragen?

Besten Dank schon mal!
Medium
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

AW: Getter wird übergangen

  Alt 17. Jun 2010, 18:27
Wieso hast du denn ausschliesslich statische class-Methoden?
Das ist sehr unschön und damit verbaust du Dir alle Möglichkeiten für die Zukunft.
Die Klasse TDBUser sollte auf jeden Fall eine ganz normale Klasse sein; ungefähr so:
Delphi-Quellcode:
TDBUser = class
private
 FID: Integer;
 FName : string;
public
  property ID: Integer read FID;
  property Name: string read GetName write SetName;
  property LastLogon:TDateTime read FLastLogon;
end;
Die Funktion GetDBUserByLogin() sieht dann ungefähr so aus:
Delphi-Quellcode:
class function TDB.GetDBUserByLogin(aLogin: string): TDBUser;
begin
  Query.SQL.Text := 'SELECT id FROM users WHERE login=:lg';
  Query.ParamByName('lg').AsString := aLogin;
  Query.Open;
  if Query.IsEmpty {besser als RecordCount=0} then
  begin
    Query.Close;
    raise EUserDoesNotExistException.Create(aLogin {welcher user nicht existiert ist wichtig zu wissen});
  end;
  result := TDBUser.Create; // neues Obj erzeugen !
  result.ID := Query.FieldByName('id').AsInteger;
  result.Name := Query.FieldByName('Name').AsString;
  ....
  Query.Close;
end;
Der Aufrufer GetDBUserByLogin() muss dann das TDBUser-Objekt freigeben.
Falls Dir das nicht gefällt, kann man auch auf Interfaces ausweichen.
Damit werden die TDBUser-Objekte automatisch freigegeben (über die Referenzzählung).
Andreas
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#3

AW: Getter wird übergangen

  Alt 17. Jun 2010, 18:35
Eben genau die Freigabefrage war der Grund für die Klassenmethoden. Es würde ja praktisch für jeden Zugriff auf einen User, wie klein auch immer, eine neue Instanz erstellt, die dann irgendwer freigeben müsste. Da die Instanz selber aber niemanden interessiert, sondern nur das, was die Properties zurück geben (das sind intern SQL Abfragen), wird auch nirgends eine Referenz auf diese behalten. Das möchte ich auch keinesfalls!

Da mir Interfaces recht unsympathisch sind, muss ich mal fragen, was ich mir so verbaue? Ableiten soll da ohnehin nie mehr jemand von, deswegen ist es ja eine private Klasse, und ich sollte sie ggf. auch noch sealed machen. Das ist auf eine ganz spezielle DB zugeschnitten, und wer auch immer darin etwas ändert hat a) auch Zugang zum Source, und bekommt b) was auffe Löffel .

Das seltsame Verhalten erklärt das allerdings leider noch nicht

Edit: IsEmpty ist schöner, danke! Welcher User da nicht gefunden wurde, wird im Moment eine Aufruftiefe höher behandelt. Da weiss ich ja auch mit welchem Login ich nachgefragt habe, und on EUserDoesNotExistException wird jetzt explizit mit einem MessageDlg behandelt. Man könnte das noch als Parameter an die Exception geben, Sinn würd das auch machen. Denken Macht viel Sinn, habs angepasst.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium (17. Jun 2010 um 18:45 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

AW: Getter wird übergangen

  Alt 17. Jun 2010, 18:37
OK, statt dem Interface würde ein Record das selbe Ergebnis bieten.
- mehrere solcher Container gleichzeitig möglich
- Delphi kümmert sich automatisch um die Freigabe
Delphi-Quellcode:
TDBUser = record
private
  FID: Integer;
  FName: string;
  FLastLogon: TDateTime;
public
  property ID: Integer read FID;
  property Name: string read FName;
  property LastLogon: TDateTime read FLastLogon;
end;
[edit]
in Delphi 7 dann ein normaler Record ohne Property (die waren eh nur für ein ReadOnly gedacht)
$2B or not $2B

Geändert von himitsu (17. Jun 2010 um 18:39 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#5

AW: Getter wird übergangen

  Alt 17. Jun 2010, 18:50
Das könnte sicherlich auch gut klappen, und wäre ggf. eine Überlegung wert. Ich hatte beim Basteln .NET im Hinterkopf, wo sowas dank GC ja usus ist.

Allerdings hilft mir das bei meinem eigentlichen Problem kein Stück weiter, da der Getter von TDB, nicht von TDB.TDBUser betroffen ist, also eine Ebene höher. Welchen Typ TDBUser dann hat, ist wohl relativ unerheblich hier, auch wenn ich die Ideen gerne annehme! Das hat nur leider nix mit dem Problem an sich zu tun
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#6

AW: Getter wird übergangen

  Alt 17. Jun 2010, 19:08
Erstmal wäre es gut, daß du erwähnst, wenn du eine andere Delphiversion, als die im Profil erwähnte, verwendest.
(inline-Typen gingen in D7 doch noch garnicht)

ups, übersehn

Dann kann es sein, daß der Compiler, Aufgrund deiner komischen Sichtbarkeitsreglungen, durchdreht.
Dein TDBUser ist als Private deklariert, aber du willst es in Public verwenden, als Result für eine Public-Methode/Property.
$2B or not $2B

Geändert von himitsu (17. Jun 2010 um 19:13 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#7

AW: Getter wird übergangen

  Alt 17. Jun 2010, 19:10
Delphi 2010 steht aber ganz klar im Ausgangspost
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
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#8

AW: Getter wird übergangen

  Alt 17. Jun 2010, 19:19
Dann kann es sein, daß der Compiler, Aufgrund deiner komischen Sichtbarkeitsreglungen, durchdreht.
Dein TDBUser ist als Private deklariert, aber du willst es in Public verwenden, als Result für eine Public-Methode/Property.
So komisch sind die eigentlich garnicht. In C# hab ich solche Konstrukte schon haufenweise verwendet. Ohne Probleme.

Ich habe aber testweise die TDBUsers als ganz eigenständige Klasse gesetzt, was leider noch immer nichts an dem Problem geändert hat. GetDBUserByLogin() wird noch immer geflissentlich gemieden, obwohl explizit auf die zugehörige Property lesend zugegriffen wird . Daran lag es leider nicht. (Was heisst leider... das wäre recht dümmlich, wenn sowas nicht in Delphi ginge )


EDIT: Okay, lustig...
Ich habe noch eine weitere Property "Users", die wie "UsersByLogin" arbeitet, aber eben eine ID statt eines Logins nimmt:
Delphi-Quellcode:
  TDB = class
  private
    class var FQuery: TUniQuery;
    class var FUser: TDBUser;
    class function GetDBUser(aUserID: Integer): TDBUser; static;
    class function GetDBUserByLogin(aLogin: string): TDBUser; static;
  public
    class property Users[aUserID: Integer]: TDBUser read GetDBUser;
    class property UsersByLogin[aLogin: string]: TDBUser read GetDBUserByLogin;
  end;

implementation

class function TDB.GetDBUser(aUserID: Integer): TDBUser;
begin
  FUser.FID := aUserID;
  result := FUser;
end;

Folgenden Methode:
Delphi-Quellcode:
procedure TframeUsers.btnResetPasswordClick(Sender: TObject);
var
  id: Integer;
begin
  id := qryUsers.FieldByName('id').AsInteger; // <---- !!!
  TDB.Users[id].Password := '';
end;
Hier wird mir vom Compiler gemeldet, dass der auf "id" zugewiesene Wert nicht mehr verwendet wird!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium (17. Jun 2010 um 19:27 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

Registriert seit: 5. Mai 2008
940 Beiträge
 
FreePascal / Lazarus
 
#9

AW: Getter wird übergangen

  Alt 17. Jun 2010, 19:29
So komisch sind die eigentlich garnicht. In C# hab ich solche Konstrukte schon haufenweise verwendet. Ohne Probleme.
Welche VS-Version hast du? Also 2010 lässt es ganz sicher nicht zu, dass man in einer Public-Methode einen Private-Typ zurückliefert. Hab ich selber schon mehrmals versucht.

Ist ja auch total sinnlos. So verhinderst du ja, dass man den Rückgabewert in einer Variable speichern kann... Wat'n Schwachsinn...
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#10

AW: Getter wird übergangen

  Alt 17. Jun 2010, 19:31
Eventuell schlägt sich auch hier wieder ein Fehler im Compiler nieder?

Versuch es mal so:
Delphi-Quellcode:
TDB = class
public
  type
    TDBUser = record
    private
      FID: Integer;
      // für jedes DB feld eben...
    public
      property ID: Integer read FID;
      property Name: string read FName;
    end;
private
  class var FQuery: TUniQuery;
  class var FUser: TDBUser;
  class function GetDBUserByLogin(aLogin: string): TDBUser; static;
public
  abc: Integer; // dummies
  xyz: String; //
  class property UsersByLogin[aLogin: string]: TDBUser read GetDBUserByLogin;
end;
Ansonsten wüßte ich auch nicht weiter (jedenfalls nicht ohne mal ein Testprojekt zum Testen zu haben).
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 15:55 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