Laden...

OR-Mapper & Datencontainer

Erstellt von Savage vor 15 Jahren Letzter Beitrag vor 15 Jahren 5.999 Views
S
Savage Themenstarter:in
100 Beiträge seit 2004
vor 15 Jahren
OR-Mapper & Datencontainer

Hallo Leute,

ich kann mich nicht entscheiden, welche Technologie ich einsetzen soll. Ich muss eine Anwendung mit einer größeren DB erstellen (ca. 120 Tabellen). Ich habe schon viel gelesen, aber weiß trotzdem nicht was ich im DataAccessLayer einsetzen soll.

Welche Datencontainer?

  • Datasets
  • Typed Datasets
  • oder einfache Entities (Klassen mit Properties & generisches Lsiten) die ich per Hand mappe

Welchen OR-Mapper (wenn überhaupt)?

  • per Hand Wert für Wert mappen?
  • das neue Entity Framework?
  • NHibernate
  • LINQ (Bin ich nicht gerade ein Freund von, weil ich SQL-Statements schneller schreibe 😉 )

Will natürlich auch ein sauberes 3-Schichten-Modell hochziehen und stelle mir auch die Frage, wo werden die Entities eingebaut (Oder ein eigenes Projekt mit Entities. welches jede Schicht kennt?).

Freue mich über jeden Tip 🙂

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo Savage

Will natürlich auch ein sauberes 3-Schichten-Modell hochziehen und stelle mir auch die Frage, wo werden die Entities eingebaut (Oder ein eigenes Projekt mit Entities. welches jede Schicht kennt?).

Ich würde sagen, deine Aussage passt soweit.
Die Entities müssen schlussendlich allen Schichten bekannt sein, das heisst sozusagen eine vertikale Schicht neben den anderen drei.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

H
154 Beiträge seit 2007
vor 15 Jahren

Hallo,
versuch mal anforderungen an deinen daten-layer zu definieren und schau was besser passt.
ich persönlich arbeite lieber mit nhibernate oder activerecord (verwendet nhibernate) als zB mit Datasets.
Grund:

  • mit nhibernate kann ich sehr einfach eine db-unabhängige persistenzschicht aufbauen da man auf sql verzichten kann
  • man kann saubere schnittstellen bauen
  • man kann ableitungen im objektmodel abbilden in der db
  • es lässt sich einfacher funktionen in den businessobjekten kapseln.
  • man kann businessobjekte als datacontract definieren und sie so in wcf services einsetzen

datasets haben natürlich auch ihre stärken. man kann echt vieles einfach lösen, und vieles ist out of the box vorhanden. ich denke datasets sind gut um schnell resultate zu haben. in grösseren, komplexen projekten ist dass (meiner meinung nach) kein kriterium. dort soll es eher darum gehen zB zur Compilezeit möglichst viel sicherheit zu haben ob die software funzt. Beispiel: sql statements in strings knallen niemals zur compilezeit, aber durchaus zur laufzeit wenn das model sich geändert hat. deshalb meine ich, ist ein persistenzlayer der auf sql verzichtet diesbezüglich sicherer.

schlussendlich ist es "geschmackssache" worauf man vertrauen will.
cheers

S
Savage Themenstarter:in
100 Beiträge seit 2004
vor 15 Jahren

Danke für eure Hinweise.

db-unabhängige persistenzschicht aufbauen da man auf sql verzichten kann

Ich habe mich noch nicht so im Detail mit OR-Mapper beschäftigt, aber kann ich dann überhaupt noch komplexere SQL-Abfragen realisieren? Bis dato habe ich solche Statements dann immer per Hand geschrieben (Joins mit Sub-Selects etc.)

F
10.010 Beiträge seit 2004
vor 15 Jahren

Natürlich kannst du die hilfen der Mapper ausschlagen und weiterhin Sql machen.

Sie werden nur noch selten gebraucht, da so sachen wie n:m Verbindungen, die ja
meist ein Join erfordern schon abgebildet sind.

143 Beiträge seit 2008
vor 15 Jahren

sql statements in strings knallen niemals zur compilezeit, aber durchaus zur laufzeit wenn das model sich geändert hat. deshalb meine ich, ist ein persistenzlayer der auf sql verzichtet diesbezüglich sicherer.

Gibt es da keine Zusatzt-tools die sql statements statisch verifizieren/überprüfen können?

Gruß Timo

H
154 Beiträge seit 2007
vor 15 Jahren

... ja du kannst auch komplexe joins ohne sql abbilden. evtl. ist so, dass du komplexe queries, die viel last auf der db erzeugen weiterhin per sql schreiben musst um einen optimalen zugriff zu erwirken, diese sql's kannst du dann so verwalten dass du sie schnell findest und nicht wild im sourcecode verstreut sind.

S
443 Beiträge seit 2008
vor 15 Jahren

@omit
das ist es eine schwierige Geschichte.
Meistens werden die SQL-String ja im Programmablauf zusammengebaut. Vorallem die WHERE Teile die man ja auch mittels den Parameter an die Datenbank schickt und somit hat man keinen "richtigen" SQL-String mehr im Code stehen, bestenfalls nur den SELECT-Teil aber der WHERE ist so gut wie immer dynamisch und somit kann man nicht mehr am Programm herum schnüfeln um die SQL-Strings zu testen, weil sie einfach nicht da sind!

mbg
Rossegger Robert
mehr fragen mehr wissen

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

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo Savage,

Eine Recht ausführliche Diskusion zu dem Thema findest du hier: typed oder untyped Dataset .

Von deinen Vorschlägen würde ich dir zu einem generischen O/R Mapper raten, da die anderen Möglichkeiten immer mindestens einen gravierenden Nachteil haben:

  • Datasets: fehlende Typensicherheit, extrem hoher Prüfaufwand (bei jedem Methodne aufruf), keinerlei Kapselung.
  • Typed Datasets: immer noch total offen, auch wenn es vorgaukelt, dass man typensicher und gekapselt arbeitet
  • oder einfache Entities (Klassen mit Properties & generisches Lsiten) die ich per Hand mappe: viel arbeit und fehleranfällig
  • per Hand Wert für Wert mappen: sieh eins höher
  • LINQ: fast so schlimm wie sql, auch keinerlei Kapselung

Ich habe mich noch nicht so im Detail mit OR-Mapper beschäftigt, aber kann ich dann überhaupt noch komplexere SQL-Abfragen realisieren? Bis dato habe ich solche Statements dann immer per Hand geschrieben (Joins mit Sub-Selects etc.)

Also je nach O/R Mapper kann man mehr oder weniger komplexe Abfragen machen (ob mit SQL oder mit anderen mitteln kann da variieren).
Aber was ich dazu sagen kann: man braucht garnicht so oft komplexe Abfragen. Zu 80-90% kommt man ohne aus und das letzte bisschen lässt sich meist mit O/R-Mapper-Mitteln dann abbilden.

Die Entities müssen schlussendlich allen Schichten bekannt sein, das heisst sozusagen eine vertikale Schicht neben den anderen drei.

Also dass halte ich für überflüssig. Die Business-Schicht sollte gegenüber der Präsentations-Schicht eine einheit aus Daten und Funktion darstellen und somit sollte die Präsentations-Schicht AUSSCHLIEßLICH die Business-Schicht kennen. (dazu hab ich mich hier schon mal lang und breit ausgelassen)

Gruß
Juy Juka

5.941 Beiträge seit 2005
vor 15 Jahren

Hallo JuyJuka

Also dass halte ich für überflüssig. Die Business-Schicht sollte gegenüber der Präsentations-Schicht eine einheit aus Daten und Funktion darstellen und somit sollte die Präsentations-Schicht AUSSCHLIEßLICH die Business-Schicht kennen. (dazu hab ich mich
>
schon mal lang und breit ausgelassen)

Deinem verlinkten Thread kann ich nicht wirklich was dazu finden.

Ich habe mich ein wenig unpräzise ausgedrückt, mindestens die Interfaces der Entities müssen ja bekannt sein, oder wie willst du das handeln?

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

S
Savage Themenstarter:in
100 Beiträge seit 2004
vor 15 Jahren

Von deinen Vorschlägen würde ich dir zu einem generischen O/R Mapper raten

Kannst du mir auch einen Konkreten empfehlen?

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo,

@Savage: Also ich bevorzuge natürlich meinen Eigenen O/R Mapper 😁 Aber bei der Aussage bin ich natürlich parteiisch

@Peter Bucher: Ich werd ein Diagramm anfertigen (das muss aber warten, bis mein anderer Rechner gebootet ist).
[EDIT]Hat doch etwas länger gedauert. Ich hoffe das nun angehängte Diagramm ist verständlich.[/EDIT]

Gruß
Juy Juka

3.728 Beiträge seit 2005
vor 15 Jahren

Kannst du mir auch einen Konkreten empfehlen?

Der Service Pack 1 des .NET Framework 3.5 bringt einen sehr guten OR-Mapper mit. Das Ganze nennt sich "ADO.NET Entity Framework". Solange Du innerhalb Deiner Lösung keine Prozessgrenzen überwinden musst, ist das Entity Framework wirklich erste Wahl. Wenn Du aber doch Prozessgrenzen überwinden musst, vergiss den ganzen OR und OOP-Quatsch am besten und nimm Typisierte DataSets.
Warum?
Weil DataRows auch nach dem serialisieren noch wissen, ob sie Added, Modified, Unchanged oder Deleted sind. Objekte wissen das leider nicht. Deshalb sind aufwändige Server-Roundtrips nötig, um den Kontext nach dem Serialisieren wieder herzustellen.
Wenn Du Interoperabel (weil Du z.B. Java-Clients bedienen musst) sein musst, sind Typisierte DataSets allerdings auch wieder nicht das Wahre. Dann ist Geschwindigkeit aber vermutlich eh nicht das Hauptkriterium. Wenns um Interoperabilität geht, hat das Entity Framework wieder die Nase vorn.

Ein ganz anderer Ansatz ist der Dokumentorientierte. Du kannst auch XML-Dokumente verwenden. Mit DOM, XPath, XSLT und Konsorten lässt sich auch ganz Komfortabel arbeiten. Nur Databinding bei Windows.Forms ist da nicht möglich. Bei ASP.NET oder WPF-Oberflächen ist das weniger tragisch, da man diese mittels XSLT teilweise direkt aus den Daten generieren kann.

Andererseitz lassen sich Typisierte DataSets auch wunderbar als XML vererbeiten. Da sie als XSD definiert werden, eignen sich Typisierte DataSets auch ideal fürs Contract-First Design.

Es kommt immer auf den Anwendungsfall an, was das Beste ist. Frag sieben Leute und Du bekommst sieben Antworten.

Wenn ich mich nicht entscheiden kann, mache ich kleine Beispiel-Anwendungen mit jeder in Frage kommenden Technologie und nehme am Ende das, was am besten geklappt hat.

143 Beiträge seit 2008
vor 15 Jahren

@Rainbird
ich find deine Beiträge immer sehr informativ, wollte deswegen nochmal nachhaken.

Weil DataRows auch nach dem serialisieren noch wissen, ob sie Added, Modified, Unchanged oder Deleted sind. Objekte wissen das leider nicht. Deshalb sind aufwändige Server-Roundtrips nötig, um den Kontext nach dem Serialisieren wieder herzustellen.

Kann man, dass nicht auch über Metadaten die man in "normalen Objekten" hält realisieren, oder ist das einfach zu umständlich.

Gruß Timo

3.728 Beiträge seit 2005
vor 15 Jahren
Status

[quote=OmitKann man, dass nicht auch über Metadaten die man in "normalen Objekten" hält realisieren, oder ist das einfach zu umständlich.
Das könnte man schon. Dann müssten die Objekte aber alle wieder eine Schnittstelle implementieren oder von einer gemeinsamen Basisklasse ableiten. Das ist bei den OR-Freaks aber verpöhnt. Denn dann könnte man auch gleich Typisierte DataSets verwenden, die ja von DataSet ableiten. In dieser Basisklasse DataSet (bzw. DataTable und DataRow) werden die von Dir angesprochenen Metdaten gespeichert und verwaltet. Bei OR-Mappern wie dem Entity Framework, LINQ2SQL oder NHibernate werden diese Metadaten außerhalb der Objekte in einem Kontext gepflegt. Im Prinzip ist das eine Hashtable, die zu jedem Objekt die Metadaten speichert. Das funktioniert auch gut, innerhalb eines Prozesses. Wenn die gefüllte Datenstruktur aber an einen anderen Prozess gesendet werden muss (z.B. via WCF/Remoting über Netzwerk vom Client zurück zum Server), nützt die Hashtable plötzlich nichts mehr, da durch die Serialisierung Kopieen der Objekte im anderen Prozess erzeugt werden. Außerdem wird der Kontext nicht mit übertragen, da er ja nicht in den Objekten selbst enthalten ist. Man könnte natürlich den Kontext auch serialisieren und ebenfalls übertragen. Das wollen die OR-Freaks aber auch nicht, da der Client mit Datenbankzuständen etc. nichts zu tun haben soll. Der OR-Mapper soll eine Black-Box sein, wo Objekte rauskommen und Objekte reingehen. Wie das alles mit der Datenbank verwurstet wird, soll den Entwickler nicht mehr kümmern müssen.
In z.B. einer ASP.NET-Anwendung, geht das oft auch auf. Bei verteilten Anwendungen (also n-Tier und nicht n-Layer) wird es mit großem Mehraufwand erkauft. Ich meine nicht nur die erhöhte Last auf der Datenbank, sondern auch jede Menge zusätzlichen Code, um nach der Serialisierung verlorene Kontexte wieder aufzubauen.

Bei Typisierten DataSets gibt es diese Probleme nicht. Stattdessen gibt es überall im Visual Studio Designer-Unterstützung, eine Standard-Implementierung für Offline-Clients in Verbindung mit SQL Server Compact und schemagestützte XML-Unterstützung (Man bedenke: Ein Typisiertes DataSet wird als XSD-Datei definiert).

Jeder Ansatz hat seine Vor- und Nachteile. Leider hat "Mode" in Sachen Software-Technologieen momentan eine viel zu große Lobby. Manchmal kommt es mir so vor, als ob vielen gar nicht mehr wichtig ist, ob eine Technologie für den Einsatzzweck gut funktioniert und leicht handhabbar ist, sondern vielmehr, ob die eingesetzte Technologie gerade "Angesagt" ist, oder nicht.

S
Savage Themenstarter:in
100 Beiträge seit 2004
vor 15 Jahren

Danke für eure Hilfen. Ich werde dann mal das EF einsetzen. Jedoch stellt sich für mich wieder die Grundsatzfrage: Kennen alle 3 Schichten die Entities vom EF welche sich im DAL befinden? Weil irgendwie müssen die ja bis zum UI runtergereicht werden? Oder wie löse ich das?

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo,

Dann müssten die Objekte aber alle wieder eine Schnittstelle implementieren oder von einer gemeinsamen Basisklasse ableiten. Das ist bei den OR-Freaks aber verpöhnt. Denn dann könnte man auch gleich Typisierte DataSets verwenden ...

Ich zähle mich selbst auch zu den ORM-Freats und ich gebe dir hier recht, dass es mit so einem externen Kontext ekelhaft wird. Es gibt aber auch O/R Mapper, die das nicht so machen (z.B. meinen eigenen oder ActiveRecor (glaube ich)).
Und nur weil alle Objekte von einer Basisklasse erben (bzw. eine Schnittstelle haben), hat eine O/R Mapper immer noch vorteile gegenüber Typisierten DataSets:

  1. Kapselung: Das DataSet bietet immer vollständigen zugriff, auch wenn man eine Typisierte Variante verwendet.
  2. Einheit von Datan und Funktion: In der OOP bilden Daten und Funktion eine einheit, bei DataSets ist das nicht so. Man schreibt immer noch zusätzliche Klassen ausen herrum, die das DataSet verarbeiten. Dadurch gehen die Vorteile von Vererbung, Polimorphie und so verloren (man kann/muss sie dann hinzu programmieren).

Danke für eure Hilfen. Ich werde dann mal das EF einsetzen. Jedoch stellt sich für mich wieder die Grundsatzfrage: Kennen alle 3 Schichten die Entities vom EF welche sich im DAL befinden? Weil irgendwie müssen die ja bis zum UI runtergereicht werden? Oder wie löse ich das?

Kenne mich mit EF nicht 100%ig aus, würde aber sagen, dass du die Entities in Logigklassen Kapselst, die Daten und Funktion zur Verfügung stellen.

Gruß
Juy Juka

84 Beiträge seit 2007
vor 15 Jahren

Im folgenden ein nützlicher Link zum Thema Enity Framework & n-Layers.
Eines des wenigen Beispiele von MS, in denen eine Architektur in ihrer Gesamtheit gesehen wird. Die Code-Samples in der MSDN sind ja nicht selten etwas.. nennen wir es naiv 😉

"The Entity Framework In Layered Architectures" (!),
http://msdn.microsoft.com/en-us/magazine/cc700340.aspx

Meiner Meinung nach ein exzellenter Artikel. Zusammen mit dem Model-Viewer-Pattern (wird ebenfalls erklärt) ergibt sich wie ich finde eine sehr saubere Architektur.

Bei dem ganzen EF-Bashing das sich derzeit in vielen Foren findet wird oft übersehen, dass die Probleme mit dem _ObjectContext _hauptsächlich in N-Tier-Anwendungen zu Schwierigkeiten führt.

Für N-Layer-Anwendungen bietet das EF auch in seiner jetzigen Form schon sehr viele Vorteile - und wer einmal eine Datanbank-Abfrage mit LINQ geschrieben hat, wird nur widerwillig wieder SQL-Strings zusammenbauen wollen.

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo Razer,

Du scheinst zwischen N-Tier- und N-Layer-Architektur zu unterscheiden. Was ist deiner Meinung nach der Unterschied?

Gruß
Juy Juka

84 Beiträge seit 2007
vor 15 Jahren

Hallo JuyJuka,

N-Tier = Schichten können auf verschiedenen Plattformen / Maschinen / o.ä. laufen, z.B. als Service etc.
N-Layer = Schichten extistieren nur lokal, innerhalb der Software, stellen also mehr eine logische Trennung dar

n-Tier Anwendungen laufen also z.B. als Service für Webanwendungen.
Die Schichten befinden sich an unterschieldichen Orten

n-Layer Anwendungen laufen z.B. als eigenständige Windowsanwendung
Die Schichten dienen vornehmlich der Erweiterbarkeit und sauberen Organisation von Zuständigkeiten u.ä..

Gruß,
Razer

2.187 Beiträge seit 2005
vor 15 Jahren

Hallo Razer,

Woher hast du die Definiton?
Ich kenne beides als N-Tier-Software, eben einmal Verteilt und einmal nicht Verteilt.

Gruß
Juy Juka

84 Beiträge seit 2007
vor 15 Jahren

Hallo JuyJuka,

zu finden z.B. unter
https://community.dynamics.com/blogs/cesardalatorre/comments/9584.aspx

Du hast aber natürlich Recht, im Endeffekt sind es ledeglich andere Begrifflichkeiten für ein und diesselbe Thematik, hier also verteilte bzw. nicht verteilte Anwendungen.

Immerhin fassen die Definitionen aber so den Aufbau bzgl. dem Ort der Schichten in jeweils eigenständige Begriffe zusammen.

3.728 Beiträge seit 2005
vor 15 Jahren
Layers oder Tiers?

Woher hast du die Definiton?
Ich kenne beides als N-Tier-Software, eben einmal Verteilt und einmal nicht Verteilt.

Die Definition ergibt sich eigentlich aus den Worten Layer und Tier. Leider gibt es im Deutschen für beide Wörter nur die Übersetzung "Schicht". Deshalb wird das oft über einen Kamm geschert. Das grundlegende Konzept ist natürlich das Selbe, aber trotzdem sind es unterschiedliche Architekturen. Bei Layers kann man z.B. Zeiger/Referenzen auf Objekte in einer anderen Schicht einsetzen. Bei Tiers geht das nicht, da Prozessgrenzen überwunden werden müssen. Folgende Methode würde z.B. in einer n-Tier-Anwendung funktionieren, aber in einer n-Layer-Anwendung zu unerwünschten Resultaten führen:


public void UpdateCustomers(List<Customer> customers)
{
    ...
}

Angenommen der Primärschlüssel der gemappten Tabelle Customer ist ein Auto-Increment-Wert, dann müssen die Schlüssel, welche die DB erzeugt hat, zurück zum Client fließen. Bei einer n-Tier-Anwendung genügt es allerdings nicht, die Objekte der Liste customers innerhalb der UpdateCustomers-Methode zu ändern, da die Methode void ist, und deshalb für die Rückgabe kein Ergebnis serialisiert und übertragen wird. In einer n-Tier-Anwendung müsste die Methode so aussehen:


public List<Customer> UpdateCustomers(List<Customer> customers)
{
    ...
}

Eine Anwendung, die nicht von vornherein verteibar konzipiert wurde, wird sich auch später nicht einfach verteilen lassen. Deshalb muss man sich bewusst für Layers oder Tiers entscheiden.