Laden...

Aufbau und Ablauf eines OR Mappers

Erstellt von Reverent vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.214 Views
R
Reverent Themenstarter:in
265 Beiträge seit 2005
vor 15 Jahren
Aufbau und Ablauf eines OR Mappers

verwendetes Datenbanksystem: <SQL Server 2005>

Hallo,

ich habe leider immer noch Verständnissprobleme mit dem sogenanten OR Mappern.

Beispiel: ich habe ein Select Statement:

SELECT anrede, vorname, nachname FROM Kunden k INNER JOIN Anrede a on k.idAnrede = a.id

Könnte mir bitte anhand des Beispiels mit den zwei Tabellen die Kassenstrukur erklären.

Ich denke ich habe zwei Klassen:
eine Klasse Kunden und eine Klasse Anrede, aber wie verbinde ich jetzt das ganze?

Das nächste ist ja, ich schreibe ja nicht das Statement in meinen Code, ich rufe ja nur eine Funktion auf z.B. GetKundenById();

Bis Dann
Reverent

F
10.010 Beiträge seit 2004
vor 15 Jahren

Es gibt nicht "den OR Mapper".

Es gibt da hunderte von, du musst dich ersteinmal für einen entscheiden,
dann kannst Du selber erstmal schauen, wie das bei diesem geht.

Aber Du solltest aufhören in "Sql zu denken".

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo Reverent,

Ich kann jetzt nicht für jeden O/R Mapper sprechen, daher mal nur für meinen eigenen:


public interface IPerson : IAisysObject
{
  decimal PersonId{get;}
  string Vorname{get;set;}
  string Nachname{get;set;}
  IAnrede Anrede{get;set;}
}

public interface IAnrede : IAisysObject
{
  decimal AnredeId{get;}
  string Text{get;set;}
}

[AutomatischerWert("person","personid")]
public class Person : AisysObject, IPerson
{
  public Person():this(null){}
  protected Person(decimal personid):this(null){this.PersonId=personid;}
  protected Person(System.Data.DataRow dr):base(dr){}
  
  [Id,Spalte]
  public decimal PersonId{get;protected set;}
  [Spalte]
  public string Vorname{get;set;}
  [Spalte]
  public string Nachname{get;set;}

  private decimal _AnredeId;
  private IAnrede _Anrede;
  [Verweis("DBAnrede")]
  public IAnrede Anrede
  {
    get
    {
      if(this._Anrede==null&&this._AnredeId!=decimal.MinValue)
      {
        Select<IAnrede> select = ImplementationAttribute.Create<Select<IAnrede>>();
        select.Objekt = ImplementationAttribute.Create<IAnrede>(this.DBAnrede);
        select.Cache = this.Cache;
        this._Anrede = select.AusfuehrenAlsFremdschluessel();
      }
      return this._Anrede;
    }
    set
    {
      this._Anrede = value;
      this.DBAnrede = (value==null?decimal.MinValue:value.AnredeId);
    }
  }
  [Spalte]
  private decimal DBAnrede{get;set;}
}

[AutomatischerWert("anrede","anredeid")]
public class Anrede : AisysObject, IAnrede
{
  public Anrede():this(null){}
  protected Anrede (decimal anredeid):this(null){this.AnredeId=anredeid;}
  protected Person(System.Data.DataRow dr):base(dr){}
  
  [Id,Spalte]
  public decimal AnredeId{get;private set;}
  
  [Spalte]
  public string Text{get;set;}
}

Und so wird dann die gesammte Personen-Tabelle abgefragt:


IEnumerable<IPerson> personen = ImplementationAttribute.Create<Select<IPerson>>().Ausfuehren();

Das wichtigste (für dich) dürfte dabei sein, dass man nicht mehr mit irgend welchen zusammen geschusterten "Tabellenbruchstücken" arbeitet, sondern immer mit (mindestens) einem gesammten, gekapseltem Objekt!

Gruß
Juy Juka

[EDIT]
PS: Ich hab kein VisualStudio zur Hand, daher ist der Code im "Freiflug" erstellt. X(
[/EDIT]

3.003 Beiträge seit 2006
vor 15 Jahren

Ich denke ich habe zwei Klassen:
eine Klasse Kunden und eine Klasse Anrede, aber wie verbinde ich jetzt das ganze?

Nunja. Containment, falls das bei den vorigen Postings nicht so rübergekommen sein sollte.


//1:1
class Kunde 
{
   public Adresse Adresse { get; set; }
}
class Adresse 
{
   public Kunde Kunde { get; set; }
}
//1:n
class Kunde
{
   public List<Adresse> Adressen { get; set; }
}
class Adresse
{
   public Kunde Kunde { get; set; }
}
//n:1
class Kunde
{
   public Adresse Adresse { get; set; }
}
class Adresse
{
   public List<Kunde> Kunden { get; set; }
}
//m:n
class Kunde
{
   public List<Adresse> Adressen { get; set; }
}
class Adresse
{
   public List<Kunde> Kunden { get; set; }
}

Gruß,

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

R
Reverent Themenstarter:in
265 Beiträge seit 2005
vor 15 Jahren

Danke für euer Antworten,

so langsam fällt der Groschen bei mir.

JuyJuka danke für dein Code, ich habe mir auch mal deinen OR Mapper runter geladen und mal eibisschen mit ihm rumprobiert.

JuyJuka, in deinem Code Beispiel sieht es so aus, als wenn du für jeden gefundenen Kunden die Anrede nachlädst.

Bis Dann
Reverent

S
443 Beiträge seit 2008
vor 15 Jahren

ich möchte da vorgreifen, es sieht nicht nur so aus, es ist auch so, ich kenne seinen OR/Mapper jetzt zwar nicht, aber das ist ein Verhalten das man Lazy-Loading nennt.
Daten erst dann laden wenn man sie braucht, bringt "meistens" einen Geschwindigkeits gewinn und auch Speicher wird nicht so viel verbraten.
Wenn man jede "Referenz" (Beziehung zwischen Tabellen) mit Eager-Loading (das Gegenteil von Lazy-Loading) lädt hat man irgendwann die ganze DB im Client-Ram liegen.
Hier ist die Schwierigkeit zu entscheiden was man Lazy und was man Eager lädt.
Wenn man für jede Adresse einzeln die Anrede von der Datenbank holt ist es, nennen wir es mal suboptimal, den das richtig teure bei Datenbankabfragen ist nicht die Abfrage an sich, sondern der Weg vom Client zur Datenbank und zurück, ob man da jetzt 1 oder 100 Datensätze holt ist im Vergleich schon fast egal.
Hier wäre ein Optimierungspotential im Cache. Wie gesagt, ich kenne seinen OR/Mapper nicht, vielleicht hat er es ja eh drin.
Die Funktionsweise eines Caches würde ich so beschreiben:
Auf der Klasse Anrede hängt ein Attribute e.g. [Cache(CacheType.All)]
dadurch erkennt der OR/Mapper das falls er das erste mal nach einer Anrede gefragt wird, geht er rüber und holt ALLE Anrede von der Datenbank und gibt die eine angefragte dem Client zurück. Die Anderen legt er in den Cache und für die zweite Anfrage erspart er sich den Weg zur Datenbank und ist damit richtig schnell, hier liegt jedoch die Schwierigkeit darin zu entscheiden was mit Änderungen auf der Datenbank zu passieren hat, wann werden die veränderten Daten nachgeladen? ginge über einen Timer der in jeder Minute einen Timestamp der Tabelle überprüft. Aber diese Entscheidung ist schwierig und ist für jede Tabelle extra zu überlegen und zu entscheiden.

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

M
110 Beiträge seit 2007
vor 15 Jahren

Grundsätzlich findest Du eine ganz gute Erklärung bei Wikipedia.

Eine Liste von O/R Mappern findest du ebenfalls bei wikipedia: http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software

Solltest Du Visual Studio 2008 und das .NET Framework 3.5 im Einsatz haben, ist LINQ vielleicht ein Ansatzpunkt um sich in das Thema einzulesen. Dort wird vielleicht auch klar, dass man ohne SQL auskommt.

Der O/R Mapper der am weitesten verbreite ist nenn sich NHibernate. Bei CodeProject gibt es dazu eine gute Einleitung wie so etwas funktioniert.

Gruss

Mirko

Mappen statt hacken mit Invist , dem .NET O/R Mapper - Code Generator

S
443 Beiträge seit 2008
vor 15 Jahren

ich lehne mich jetzt mal sehr weit aus dem Fenster, sehr weit ...
[ausdemFensterLehn]
ich finde NHibernate ein bisschen out-of-Date, wieso XML-Mappings schreiben, die mal nicht leicht sind und wenn man viel vom NHibernate will auch sehr schwer werden können.
Ich würde mir einen OR-Mapper suchen der mit ".Net Bordmitteln" auskommt, z.b. mit Attributen. ich glaube juyjake's OR/Mapper ist so einer
So einer ist meiner Ansicht nach auch wesentlich schneller in der Einarbeitungszeit
da hat man so 10 Attribute die "eigenständig" funktionieren und die Hilfe dazu gelesen und man weis nach 2 Tagen was geht und was nicht, bei NHibernate hatte ich nach einem Monat noch immer keine Ahnung ob es wirklich nicht geht, oder ob ich zu blöd bin das Mapping richtig zu schreiben.
NHibernate hat meiner Ansicht nach die Marktführung weil es der "erste" war, nicht weil der der beste ist.
[/ausdemFensterLehn]
Bitte keine Steine werfen

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

F
10.010 Beiträge seit 2004
vor 15 Jahren

Könnte es sein, das du ca. 2 Jahre nichts mehr über NHibernate gelesen hast?

  1. Gibt es mit ActiveRecord einen wirklich guten "Aufsatz", der mit Attributen arbeitet.

  2. Gibt es mit Fluent NHibernate einen weiteren Ansatz der ohne XML auskommt.

  3. Sind alle diese Attributgetriebenen ORMapper dann nicht zu gebrauchen,
    wenn man nicht veränderbare POCO's hat.

  4. Da auch LinQ2NHibernate vorhanden ist .....

Und NHibernate hat gegenüber all denen die Du genannt hast den Vorteil,
das es sich bewährt hat.

Das müssen alle anderen erst noch beweisen.

S
443 Beiträge seit 2008
vor 15 Jahren

Es war voriges Jahr im Sommer wo ich mir das Teil angesehen habe und war halt nicht sehr glücklich damit.

was sind POCO's?

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

M
110 Beiträge seit 2007
vor 15 Jahren

O/R Mapper ist nicht gleich O/R Mapper.

Grundsätzlich ist erst mal die Absicht eines Mappers zu beachten. Möchte man eine Klassenstruktur erstellen anhand einer Datenbank oder ist man doch eher auf dem Trip, dass man starke vererbungen möchte und daraus das Script für eine Datenbank generiert.

Das ist reine Geschmacksache.

Gruss

Mirko

Mappen statt hacken mit Invist , dem .NET O/R Mapper - Code Generator

F
10.010 Beiträge seit 2004
vor 15 Jahren

@spike24:

P(lain) O(ld) C(lr) O(bject).
Könnte man aber auch durch suchen mal finden.

Und ich kann mich noch an unsere Diskusion bez. Gentle erinnern.

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo,

@Reverent und spike24: Ja, die Anreden werden seperat "lazy" geladen. Das Caching ist auch mit enthalten und verhindert Datenbankzugriffe, falls der Primärschlüssel in einer Abfrage enthalten ist und das entsprechende Objekt schon geladen ist.

select.Cache = this.Cache;  
  

@mirkom76 zum Ersten: Was hat Linq mit O/R Mapping zu tun? LinqToSql hat schon ehr was mit dem Thema zu tun, ist aber kein O/R Mapper. (Es ist mehr oder weniger ein Aufsazt für SQL, damit der Compiler ein paar überprüfungen machen kann.)

@mirkom76 zum Zweiten: Du hast recht, es gibt mehrer Ansätze für O/R Mapper. Der häufigste und Verbreitetste ist, dass ein Objekt einer Datenzeile in der Datenbank entspricht. Es gibt z.B. noch die Variante, das ein Objekt einer Tabelle in der Datenbank entspricht, aber der "natürlichste" Ansazt ist das Objekt=Datensatz, da diese Konstellation am ähnlichsten ist.
Was ich jedoch glaube, dass man beachten sollte ist: Ein O/R Mapper ist nicht das gleiche wie ein Code-Generator! Viele O/R Mapper enthalten zwar Code-Generatoren, es handelt sich aber meiner Meinung nach um zwei verschiedene Aufgaben/Lösungen.
(Ich hab zumindest mirkom76's Aussag so verstandne, dass er beides mischt.)

Thema NHibernate
Ich habe nie mit NHibernate gearbeitet, da ich das mit dem XML-Mapping gesehen habe und nicht wusste, dass es ActiveRecord gibt. Und dieses XML-Gezeugs war für mich ein definitives K.O.-Kriterium.
Da NHibernate sich aber hält, weiter entwickelt wird und scheinber recht stabiel ist, würde ich jedem Empfehlen das auch mal auszuprobieren.
Man sollte möglichst viele O/R Mapper mal ausprobieren, bevor man sich festlegt.

Gruß
Juy Juka

742 Beiträge seit 2005
vor 15 Jahren

Gerade wegen den XML Mapping Files finde ich NHibernate so toll. Nur damit lassen sich wirklich Contracts mit puren Entitäten (POCOs) gestalten. Das ganze Attribute Zeug macht die Technologieunabhängigkeit echt zunichte.

Fluent Hibernate wäre auch noch ne Alternative aber Attribute gehen mal gar nicht.

F
10.010 Beiträge seit 2004
vor 15 Jahren

Ist wie mit dem Appserver, den braucht auch fast keiner, aber Enterprisesoftware
geht eigentlich nicht ohne.

Und genauso ist es mit POCO's.
Wer ständig boundaries durchbrechen muss, ist natürlich froh das das mit NHibernate geht,
aber die meiste SW ist eher als Smartclient ausgelegt, wo die
BO nicht unbedingt POCO's sein müssen.
Hier werden meist die Daten nur von/zur DB transportiert, und da
ist der ActiveRecord Ansatz deutlich produktiver.
Und da man da dann sowieso schon komplexe Objekte hat ( siehe z.b. CSLA )
kommt es auf die "paar Attribute" auch nicht mehr an, man ist eh gebunden.

Es kommt eben darauf an, was man braucht.

S
443 Beiträge seit 2008
vor 15 Jahren

@FZelle
hab nach POCO gesucht, aber nur Einträge zu einem Möbelhaus gefunden.
Mit Plain Old CLR Object war die Suche erfolgreicher, mir war die Abkürzung nicht bekannt. Und wenn die Entwicklung von Gentle nicht schon vor meinem finden eingestellt worden wäre, wäre es sicher ein toller OR/Mapper geworden 😉

@malignate:
was meinst Du mit:
macht die Technologieunabhängigkeit echt zunichte.
Du arbeitest ja einerseits mit .Net und es ist ja eigentlich die ureigenste Sache des OR/Mappers selbst wie er erkennt wo was hingehört.
Was ich an den Attributen eben als Vorteil finde habe ich ja schon gesagt und um NHibernate richtig bedienen zu können, muss man desen XML-Syntax kennen und da bin ich mit der Hilfe absolut nicht klar gekommen, N:M Beziehungen waren für mich echt nicht machbar.

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

M
110 Beiträge seit 2007
vor 15 Jahren

Ich persönlich stehe mehr auf Attribute. Aber das ist ja jedem selber überlassen.

Aspect-orientierte Programmierrung setzt auch auf Attribute auf. Also können Attribute nicht schlecht sein. Schliesslich hat Java mit Annotations dieses Prinzip übernommen.

Es aber geschmackssache.

Gruss

Mirko

Mappen statt hacken mit Invist , dem .NET O/R Mapper - Code Generator