AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi [RTTI] RttiProperty aus Property von Instanz erzeugen

[RTTI] RttiProperty aus Property von Instanz erzeugen

Ein Thema von s.h.a.r.k · begonnen am 25. Mär 2010 · letzter Beitrag vom 31. Mär 2010
Antwort Antwort
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#1

[RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 25. Mär 2010, 16:13
Hallo,

hänge gerade mal wieder an einem neuen Problem mit Rtti und ich weiß nicht, wie ich das machen sollte. Ich habe mehrere Properties, die mit Werten aus der Datenbank befüllt werden. Die Setter-Methoden dieser Properties sollen auf eine generische Methode verweisen, die das Setzen der Werte für alle relevanten Properties übernehmen kann. Wichtig hierbei ist die Prüfung auf das Attribut NotNull, d.h. beim Setzen eine Wertes wird geprüft, ob ein Null-Wert gesetzt werden darf oder nicht.

Hier ein vereinfachtes Szenario, sodass das verständlicher wird:

Delphi-Quellcode:
TBlub = class(TObject)
private
  FNotNullProperties : TStringList; // wird im Konstruktor mit
  FPropA : Variant;
  FPropB : Variant;
  procedure GenericSetter(const AValue: Variant; const ADestVar: PVariant; const AProperty: TRttiProperty);
  procedure SetPropA(const AValue: Variant);
  procedure SetPropB(const AValue: Variant);
public
  [NotNull]
  property PropA : Variant read FPropA write SetPropA;
  property PropB : Variant read FPropB write SetPropB;
end;

procedure TBlub.GenericSetter(const AValue: Variant; const ADestVar: PVariant; const AProperty: TRttiProperty);
var
  rContext : TRttiContext;
  rType : TRttiType;
begin
  if (AValue <> ADestVar^) then
  begin
    if (AValue <> Null) then
    begin
      ADestVar^ := AValue;
    end
    else begin
      // Prüfen, ob Property überhaupt Null werden darf, denn wenn nicht dann muss eine Exception
      // geworfen werden
      if (FNotNullProperties.IndexOf(AProperty.Name) <> -1) then
        raise Exception.Create('...');
      ADestVar^ := Null;
    end;
  end;
end;

procedure TBlub.SetPropA(const AValue: Variant);
begin
  GenericSetter(AValue, FPropA, GetRttiProperty(PropA)); // GetRttiPropertyist eine fiktive Funktion
end;

procedure TBlub.SetPropB(const AValue: Variant);
begin
  GenericSetter(AValue, FPropB, GetRttiProperty(PropB)); // GetRttiPropertyist eine fiktive Funktion
end;
So, nun ist es ja so, dass, wie im Quelltext schon geschrieben, GetRttiProperty eine fiktive Funktion ist, die ich suche. Ich will eben aus der Property PropA bzw. PropB ein TRttiProperty-Objekt machen, ohne dabei auf einen String zurückgreifen zu müssen. Sollte sich nämlich mal etwas an den Properties ändern, so kann ich nicht einfach das Refactoring anwerfen, sondern darf selbst nach Strings suchen, was alles andere als sauber wäre.

Ich hoffe, dass mir hier jemand weiter helfen kann. Bin gerade echt am verzweifeln
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#2

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 25. Mär 2010, 17:59
So funktioniert aber kein mir bekannter O/R-Mapper (wenn es auch nur annähernd in diese Richtung gehen soll). Die Datenobjekte sollten reine PODOs (Plain Old Java Delphi Objects) sein, die ganz gewöhnliche Properties besitzen. Erst von außen reflektiert ein Helferlein über diese Klassen und füllt sie mit den Daten aus der DB - den Klassen selbst sieht man das überhaupt nicht an.
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
Benutzerbild von chaosben
chaosben

Registriert seit: 27. Apr 2005
Ort: Görlitz
1.358 Beiträge
 
Delphi XE2 Professional
 
#3

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 26. Mär 2010, 07:35
Vielleicht hilft dir unsere RTTIHelper-Unit weiter.
Benjamin Schwarze
If I have seen further it is by standing on the shoulders of Giants. (Isaac Newton)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.007 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 26. Mär 2010, 08:00
Zitat von Khabarakh:
So funktioniert aber kein mir bekannter O/R-Mapper (wenn es auch nur annähernd in diese Richtung gehen soll). Die Datenobjekte sollten reine PODOs (Plain Old Java Delphi Objects) sein, die ganz gewöhnliche Properties besitzen. Erst von außen reflektiert ein Helferlein über diese Klassen und füllt sie mit den Daten aus der DB - den Klassen selbst sieht man das überhaupt nicht an.
Sehe ich genauso. Das Datenobjekt sollte keinen Code enthalten, der für das O/R-Mapping zuständig ist. Einzig die mit Delphi 2010 eingeführten Attribute halte ich für eine Möglichkeit einer Klasse Mapping Infos mitzugeben (obwohl auch hier teilweise die Meinungen auseinander gehen).
Man sieht an deinem Beispiel schon, welche Nachteile du hast. Man muss bei neuen Properties speziellen Code schreiben und kann nicht einfach eine simple neue Property in die Klasse einbauen.

Zu deiner eigentlichen Frage: ich kenne keine Möglichkeit über eine Property-"Referenz" an die RTTI Information dieser zu kommen.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#5

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 26. Mär 2010, 13:31
Jo, es soll im Endeffekt ein O/R-Mapping statt finden. Ich fand das Attribut-Prinzip ganz hilfreich für genau so etwas. Ich habe auch für jede Property ein Attribut, welchem ich einen String übergebe. Dieser entspricht einer Spalte aus der Datenbank. Somit baue ich im Moment meine Abbildung zusammen, d.h. die Properties können einen anderen Namen tragen als die Spalten aus der DB. Ich habe mir schon überlegt, das in einer XML zu definieren oder über ein Array zu lösen, aber da habe ich *immer* das Problem, dass kein Refactoring sinnvoll greift, wenn ich denn einmal eine Property umbenennen will. Daher hielt ich das für die beste Lösung.

Und genau das wollte ich nun eigentlich für genau das oben beschriebene Problem auch habe. Änderungen sollen einfach via Refactoring möglich sein, ohne, dass ich nicht x-beliebig viele andere Stellen anspringen muss und Strings ändern sollte. Nur ich seh schon, ich muss das irgendwie anders gestalten.

Abseits davon: Wie machen das "normale" O/R-Mapper denn? Es wird ja ein Abbildungs-Verzeichnis benötigt. Wo wird das gespeichert? Wie werden zusätzliche Dinge beachtet? Not Null z.B.? Wird das alles fix in einen Controller implementiert?
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#6

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 26. Mär 2010, 15:24
Gegen Attribute haben wir doch gar nichts eingewendet . Es ging lediglich um den Setter-Code.

Im einfachsten Fall wird für alle Public Properties jeweils eine gleichnamige DB-Spalte gesucht. Durch Attribute können sie zusätzlich umbenannt oder ignoriert werden, auch Validation-Informationen wie NotNull kannst du damit durchaus hinzufügen.
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#7

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 26. Mär 2010, 18:31
Zitat von Khabarakh:
Im einfachsten Fall wird für alle Public Properties jeweils eine gleichnamige DB-Spalte gesucht. Durch Attribute können sie zusätzlich umbenannt oder ignoriert werden, auch Validation-Informationen wie NotNull kannst du damit durchaus hinzufügen.
Ja, klar, aber ich muss diesen Code dann immer in die Setter-Methoden packen und kann dies ja nicht auf eine Methode reduzieren. Sollte sich dann mal etwas an dem System ändern muss ich es in *allen* Setter-Methoden ändern und nicht nur in einer. Das finde ich nicht wirklich zufriedenstellend.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#8

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 27. Mär 2010, 15:25
Ah, ich habe mich auf das Einfügen der DB-Daten in die Entities konzentriert, eben der erste und wahrscheinlich leichteste Schritt auf dem Weg zu einem O/RM . Für solche Sachen wie Change Tracking und Validation muss tatsächlich etwas im Setter geschehen, da hast du schon recht. Wenn man also ein Validate('ThisProperty') vermeiden will, sehe ich bei statisch typisierten Sprachen nur zwei Möglichkeiten:
  • Runtime Proxies: Alle Properties werden als virtual markiert und zur Laufzeit vom Mapper-System überschrieben. So machen das zum Beispiel Hibernate in Java und NHibernate & Entity Framework in .NET. In Delphi dürftest du da aber relativ chancenlos sein.
  • Code Generation: Wenn man den Code selbst nicht schreiben will, muss er eben automatisch aus dem Designer/der XML-Config/... erstellt werden . Damit sind die Property-Namen garantiert aktuell, von der generierten Klasse kann dann abgeleitet und entsprechende virtuelle Methoden wie "PropAChanged" überschrieben werden. So macht es LINQ To SQL.
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#9

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 30. Mär 2010, 15:38
Irgendwie ist das aber immer noch nicht so ganz das was ich mir darunter vorgestellt habe. Selbst wenn ich intern die Daten nicht wie eine Property handle (z.B. in einem passenden indexierten Container), führt das früher oder später zu ungewollten Problemen, da ich dann wieder keine Attribute für die einzelnen Werte anwenden kann. Ich stoße dabei immer wieder an Ecken, die nicht so toll sind.

Es wäre echt wünschenswert aus einer Property eine TRttiProperty-Referenz zu erhalten. Mal schauen, was das neue Delphi so bringen wird.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#10

Re: [RTTI] RttiProperty aus Property von Instanz erzeugen

  Alt 31. Mär 2010, 22:58
Ich habe nun eine Lösung, die über die Setter-Methode einer Property läuft. Diese Idee funktioniert allerdings nur unter der Voraussetzung, dass jede Property eine eindeutige und einzigartige Setter-Methode hat, denn wenn für mehrere Properties ein und die selbe Setter-Methode verwendet wird (was ja unter Umständen der Fall sein kann), so wäre dies keine eindeutige Abbildung und so käme auch keine korrekt Lösung heraus.

Delphi-Quellcode:
// Prozeduraler Typ für Parameter
TMyProc = procedure (const Value: Variant) of object;

// Test-Klasse ;)
TTestObject = class(TObject)
private
  FPropA : String;
  FPropB : String;
  function GetPropA(): String;
  procedure SetPropA(const Value: String);
  function GetPropB(): String;
  procedure SetPropB(const Value: String);
public
  property PropA : Stringread GetPropA write SetPropA;
  property PropB : Stringread GetPropB write SetPropB;
  function GetRttiPropertyBySetter(const AMethod: TMyProc): TRttiProperty;
end;

implementation

{ TTestObject }

function TTestObject.GetPropA(): String;
begin
  Result := FPropA;
end;

procedure TTestObject.SetPropA(const Value: String);
var
  pt : Pointer;
begin
  { ... }
end;

function TTestObject.GetPropB(): String;
begin
  Result := FPropA;
end;

procedure TTestObject.SetPropB(const Value: String);
begin
  { ... }
end;

function TTestObject.GetRttiPropertyBySetter(const AMethod: TMyProc): TRttiProperty;
var
  pt : Pointer;
  rContext : TRttiContext;
  rType : TRttiType;
  rProperty : TRttiProperty;
  rPropInfo : PPropInfo;
begin
  Result := nil;

  // Pointer auf Setter-Methode holen
  pt := @AMethod;

  rContext := TRttiContext.Create();
  try
    rType := rContext.GetType(Self.ClassType);

    // Property für Property durchgehen, bis eine gefunden wurde
    // die eine passende Setter-Methode (Erkennung via Pointer) hat.
    for rProperty in rType.GetDeclaredProperties do
    begin
      rPropInfo := TRttiInstanceProperty(rProperty).PropInfo;
      if (rPropInfo.SetProc = pt) then
      begin
        Result := rProperty;
        exit;
      end;
    end;
  finally
    rContext.Free();
  end;
end;
Vielleicht hilft das ja mal jemandem. Sinnvoll ist diese Methode im Moment nur, wenn diese intern (private) verwendet wird, oder man setzt die Setter-Methoden public, sodass man darauf auch von außen zugreifen kann.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 18:48 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