Ich habe es jetzt nach Monaten voller Projekte mal geschafft, mich mit ein paar Neuerungen die Microsoft in den letzten Monaten (Jahren) auf den Weg gebracht hat, zu beschäftigen - hängen geblieben bin ich bei LINQ.
Meine ursprüngliche Skepsis verwischt langsam ein wenig, obwohl ich nach wie vor nicht so recht weiß was ich davon halten soll.
Ich denke es ist wie damals, als ich das erste Mal von ASP.NET gehört und die ersten Demos gesehen habe - da habe ich mich sofort gefragt, wer um alles in der Welt die Kontrolle über den generierten HTML- und CSS-Code aus der Hand geben will. Heute kann ich mir nicht mehr vorstellen z.B. Eingabevalidierungen ohne ValidationControls von Hand zu machen.
Das Gleiche ist es jetzt mit LINQ - seit über einem halben Jahrzehnt (noch gar nicht so lange also, aber lang genug um sich dran zu gewöhnen) erstelle ich meine SQL-Statements selbst, seit einigen Jahren ausschließlich in Stored Procedures. Es war für mich meistens lästiges Beiwerk, nicht zuletzt wegen der beschränkten Tools (bis heute gibt es für den SQL-Server meines Wissens nach kein vernünftiges IntelliSense!), aber dennoch hatte das alles einen Vorteil: ich habe annähernd bis ins letzte Detail gewusst, was passiert - keinen Overhead erzeugt, immer genau den Überblick gehabt - über jedes Feld, jede Tabelle.
Ich habe deshalb auch absichtlich auf (Typed) Datasets verzichtet, schon immer - warum denn bitte diese Masse an Code und performancefressenden Aktionen lostreten, nur um ein Feld aus einer Tabelle auszulesen?
Mit LINQ (to SQL) komme ich nun etwas ins Grübeln und mein sorgsam geschaffenes Weltbild gerät etwas ins Wanken.
Gründe:
- 100%ige IntelliSense-Unterstützung für alle Datenbankobjekte in Visual Studio. Kein Trial & Error mehr in der SQL-Konsole.
- Dementsprechend volle Debug-Unterstützung - geringere Fehleranfälligkeit, einfacheres Testen.
- Sehr guter ORM-Designer in Visual Studio, der gleichzeitig sehr einfach ist.
- Weiterhin volle Flexibilität was die Verwendung von Stored Procedures angeht.
- Delay Loading: bestimmte Felder können erst dann geladen werden, wenn auf sie zugegriffen wird. Das kann richtig Performance sparen - bisher habe ich dafür dann gesonderte SPROCs geschrieben oder entsprechend mit Parametern Extraarbeit betrieben.
- Insgesamt viel schnelleres Arbeiten, Stichwort ASP.NET-Validation-Controls: LINQ to SQL erspart einem eine Menge Arbeit.
Warum ich noch nicht vollends überzeugt bin:
- LINQ to SQL ist ein auf den MS SQL Server beschränkter O/R-Mapper. Theoretisch ist es auch möglich andere Datenbanken und Datenquellen anzusprechen, aber ist der Aufwand im Fall der Fälle gerechtfertigt? Soll heißen: begibt man sich nicht wieder in eine unnötige Abhängigkeit/Einbahnstraße?
- Mir fehlen noch Hintergrundinfos um evtl. Overhead abschätzen zu können, Stichwort Typed DataSet. Wann werden SQL-Commands in Richtung Datenbank geschickt? Wie verhält es sich bei vielen Zugriffen? D.h. wie sieht die Performance im Vergleich zu meiner bisherigen Lösung SPROC/DataReader + manuelles Mapping auf meine Objekte aus?
Die Gretchenfrage:
Mein Weltbild sieht im Moment in den meisten Projekten 3+1 Schichten vor:
- GUI
WebForms und/oder UserControls usw. Holen und liefern Daten an den Business Layer, kein Kontakt zum Data Layer - damit kann ich die darunter liegende Datenbank einfach austauschen.
- Business Layer
Klassen und Methoden, die Daten entgegennehmen, verarbeiten, ausliefern (z.B. Datensätze einer Suche).
- Data Layer
Wird ausschließlich vom Business Layer angesprochen, stellt Klassen und Methoden bereit, die die Daten aus der Datenquelle liefern, und vorher auf die Geschäftsobjekte mappen. D.h. ich hole bsp. mit einem SqlCommand auf eine Stored Procedure alle Datensätze einer Suchanfrage, erzeuge mittels DataReader.Read() in einer Schleife die Ergebnis-Objekte (ergebnis.ID = (int)reader[0];) und füge diese Objekte dann einer Liste hinzu die ich dann zurückgebe.
- Business Objects
Geschäftsobjekte, etwa "Ergebnis" für eine Suchanfrage, Listen ("ErgeignisCollection") und Aufzählungen.
Mehrheitlich ist es zurückblickend so gewesen, dass die Objekte in der Datenbank (Tabellen) in etwa denen entsprachen, die ich auch in der Anwendung verwendet habe.
Da liegt jetzt der Gedanke nahe, um zur Gretchenfrage zu kommen, auf die eigenen Geschäftsobjekte zu verzichten und stattdessen ausschließlich die von LINQ to SQL generierten Objekte zu benutzen. Deren Naming kann man ja anpassen, genauso kann man sie erweitern, von anderen Basisklassen ableiten usw. Das ist vielleicht nicht besonders schön (weil man in die Autogenerierung eingreift), aber - da sind wir wieder bei den Validation-Controls - es spart wieder einiges an Zeit und Tipparbeit.
Gleichzeitig vermischt man aber letztlich wieder alles, weil man keine klare Trennung mehr hat - die Objekte werden schließlich vom "Data Layer" bereitgestellt, bzw. erzeugt.
Fragen über Fragen
Mal sehen für was ich mich entscheide, ich denke auf jeden Fall, dass sich ein Einsatz von LINQ to SQL im ein oder anderen Projekt dieses Jahr lohnt - spätestens dann bin ich auch schlauer, was sinnvoll ist und was sich in der Praxis als weniger tauglich herausstellt.
Wahrscheinlich werde ich aber eher bei meinem bewährten Modell bleiben und schlicht innerhalb der Methoden im Data Layer LINQ einsetzen.
Meinungen sind übrigens gerne willkommen - per Kommentar wie per Mail :-).