Laden...

ORM im Selbstbau oder dynamisches Nachladen von Eigenschaften?

Erstellt von MHA vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.763 Views
M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren
ORM im Selbstbau oder dynamisches Nachladen von Eigenschaften?

verwendetes Datenbanksystem: Firebird

Hallo zusammen!

Ich hab ein Problem. Und zwar hab ich zum Beispiel für jede Tabelle einer DB eine Klasse (Bsp.: Person), welche alle Eigenschaften aber keinerlei Funktionalität bereitstellt.


class Person
{
  public string Name { get; set; }
  ...
  public int LandID { get; set; }
  public string Land { get; set; }
  ...
}

Dann gibt es in miener Datenzugriffskomponente jeweils eine Klasse DataAdapter, welche Methoden zum laden, speichern, update usw. bereitstellt.


class PersonDataAdapter
{
  public List<Person> GetAll() {...}
  public Person GetByName(string name) {...}
  ...
  public bool Save(Person) {...}
  ...
}

Nun zum Problem: Ich will aus Performance-Gründen nicht bei jedem Laden eines Objektes alle Eigenschaften laden müssen, welche in anderen Tabellen stecken.
Also im Beipiel die Eigenschaft "Land", welche den Namen des Landes der Person beinhaltet, sollte erst dann ermittelt werden müssen, wenn auch wirklich darauf zugegriffen wird. In etwa so:


class Person
{
  private int _landID;
  public int LandID
  {
    set
    {
      if (_landID != value)
        _strLand = string.Empty;
      _landID = value;
    }

    get { return _landID; }
  }

  private string _strLand;
  public string strLand
  {
    get
    {
      if (string.IsNullOrEmpty(_strLand) && (_landID >= 0))
        _strLand = GetLandByID(_landID).Bezeichnung;
      return _strLand;
    }
  } 
}

ABER "GetLandByID" kann und darf es in der Klasse "Person" nicht geben, da "Person" nix von der DB weiß und auch gar nicht wissen soll!
Wie also kann ich das lösen???

Ich hoffe ich konnte mein Problem einigermaßen verständlich erläutern!

Gruß
Marc

742 Beiträge seit 2005
vor 13 Jahren

Ich sehe 3 Möglichkeiten:

  1. Du kannst zum Beispiel mit dynamisch generiertem Code arbeiten. Deine Klasse Person hat nur virtuelle Properties. Zur Laufzeit erstellst du dann eine von Person abgeleitete Klasse, die für die Properties eine entsprechende Implementierung bereitstellt.

Vielleicht hat das Rhino Framework schon entsprechende Implementierungen.

  1. Eine andere Möglichkeit wäre ein AOP Framework, dann hättest du ein Attribute 'Lazy' oder so.

  2. Die dritte und einfachste Alternative wäre die Klasse Lazy: http://msdn.microsoft.com/en-us/library/dd642331.aspx

M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren

Danke für deine schnelle Antwort!

Hauptsächlich gehts mir darum eine korrekte Trennung zwischen meiner Datenzugriffskomponente, den Datenobjekten und der GUI zu erhalten.

Bisher ist es so, das in der Gui-App eine Instanz der Datenzugriffskomponente erzeugt wird

PersonDataAdapter pda = new PersondataAdapter(DBConnectionString)

und mit deren Hilfe können dann Operationen ausgeführt werden:

List<Person> pListe = dpa.GetAll();

Bisher werden immer alle Eigenschaften von "Person" befüllt. Wenn ich nun aber einzelne Eigenschaften erst bei Bedarf nachladen will, bräuchte das Objekt "Person" bei dem Ansatz, wie ich ihn in meiner Frage geposted habe, Kenntniss von der DB. Und das darf nicht sein!

R
103 Beiträge seit 2009
vor 13 Jahren

Das muss meines Erachtens auch nicht so sein. Mit AOP oder einer mit virtuellen Methoden abgleiteten Klasse von Person (Varianten 1 und 2 vom vorigen Post) kannst Du den Zugriff auf die Property "Land" auf eine Methode in der Datenzugriffskomponente umleiten.

Die gui greift dann auf die "Land" property zu ohne zu wissen, dass die DatenzugriffsKomponente aufgerufen wird (interceptor).

Wir haben das hier bei uns in der Firma mit dem AOP Framework Postsharp gemacht (also variante 2), es gibt aber auch noch andere wie Rhino Mocks, Castle Dynamic Proxy...

Einfacher von der Implementierung und vom Einarbeitungsaufwand wäre aber für deinen konkreten Fall wahrscheinlich Variante 1.

M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren

Manchmal muss man nur einen Schubser bekommen!

Das Proxy-Muster könnte mein Problem lösen.

Die DataAdapter liefern nur Proxys der eigentlichen Objekte. Wenn dann auf eine Eigenschaft zugegriffen wird, kann der Proxy entscheiden, ob der Zugriff nur auf das reale Objekt weitergeleitet wird oder ob erst nachgeladen werden muss. Damit kann ich die Trennung weiterhinn aufrechterhalten!

Vielen Dank für eure Mühe!

Gruß
Marc

742 Beiträge seit 2005
vor 13 Jahren

Ich denke Variante 3 wäre am einfachsten. Du musst nur alle Properties suchen, die Lazy<?> als Property Type verwenden und dann eine Instanz von Lazy<?> zuweisen, die die Info aus der Datenbank nachlädt.

Vorteile:

  1. Keine weiteren Abhängigkeiten zu PostSharp oder Rhino Mocks or whatever.

  2. Du kannst ohne Zusatzinfos leicht entscheiden, welche Werte nachgeladen werden sollen und welche nicht.

  3. Es ist wirklich einfach zu implementieren.

  4. Deine Properties müssen nicht virtuell sein.

PS: Ich würde generell auf jeden Fall noch das PrimaryId Property mit einem Attribut [Id] versehen, dann kann das leicht ausgelesen werden und dein PersonAdapter kann dann sehr leicht von TableAdapter ableiten und muss nur noch die konkreten SQL Statements implementieren. Alternativ auch seperare Mapping Info.

PPS: Bei Variante 2 würde ich noch PostSharp verwenden um INotifyPropertyChanged zu implementieren (wenn du schon dabei bist).

M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren

Ja, die Lazy<T> - Variante klingt gut, gibt es aber erst ab Framework Version 4 und mein Projekt läuft unter 3.5 !

742 Beiträge seit 2005
vor 13 Jahren

Kannst dir ja selber machen, mit Reflector zum Beispiel 😄

M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren

Auch wieder wahr 😉

742 Beiträge seit 2005
vor 13 Jahren

Mir ist gerade noch was eingefallne, was nur bedingt zum Thema passt:

Falls du folgenden Link nicht kennst: Sehr empfehlenswert, bei Queries mit vielen Ergebnissätzen bringt das gut was an Performance.

http://www.codeproject.com/KB/cs/DynamicCodeVsReflection.aspx

M
MHA Themenstarter:in
8 Beiträge seit 2009
vor 13 Jahren

Danke, den Link kenne ich noch nicht, schaue ich mir gleich mal an!