Jeder Entwickler kennt die Arbeit an der Datenzugriffsschicht. Die Arbeit ist langweilig und fehleranfällig und man hat alles schon so oft geschrieben, dass man die einzelnen Funktionen schon nicht mehr sehen kann. Oft wünscht man sich eine Möglichkeit, mit Hilfe eines Codebuilders unkompliziert und On-the-fly die passenden Objekte aus Tabellen und Stored procedures zu generieren.
Genau dieses Ziel hat Rob Conery mit seinem Projekt SubSonic im Auge. Rob Conery ist ein Entwickler aus Hawaii und unter anderem durch die Entwicklung des Commerce Starter Kits bekannt. Der Quellcode ist auf CodePlex verfügbar und wird derzeit sehr rege weiter entwickelt.
Ich habe im Zuge eines Refactorings das Data Access Layers eines Webservices auf SubSonic umgestellt. Ursprünglich hatte das DAL ca. 2000 Zeilen nachdem ich SubSonic in das DAL eingebaut habe, konnte ich den Code auf ca. 600 Zeilen verringern. Der Webservice ist im Produktiveinsatz und funktioniert hervorragend.
SubSonic orientiert sich am Design Pattern ActiveRecord, d.h. eine Klasse pro Datenbanktabelle (und Stored Procedure) und einem Objekt pro Zeile.
SubSonic beinhaltet einen BuildProvider der es ermöglicht zur Entwurfszeit Änderungen des Datenbankschemas direkt in den Klassen zu reflektieren, d.h. jede Änderung z.B. eines Felds oder einer neuen Tabelle steht direkt bei der Entwicklung zur Verfügung. Voraussetzung ist dazu allerdings eine Full Trust Umgebung die beim Deployment auf dem Produktivsystem eventuell nicht zur Verfügung steht. Dazu stellt SubSonic zusätzlich einen Sourcecode Generator zur Verfügung mit dem man die Klassen komplett erzeugen und dann mit dem Projekt kompilieren und ausliefern kann. Derzeit ist mit SubText eine zusätzliche Option in Arbeit, mit der man diesen Prozeß, der derzit nur über ASP.NET Seiten unterstützt wird, innerhalb eines Buildprozesses automatisieren kann.
Voraussetzungen für den Einsatz von SubSonic ist Visual Studio Express Webedition und SQL Server Express. Weitere unterstützte Datenbanken sind MySQL sowie jede über die Enterprise Library unterstützte Datenbank. Ein weiteres nettes Feature ist die Möglichkeit das komplette Datenbankschema sowie die enthaltenen Daten als SQL Skript generieren zu lassen und später auf dem Zielsystem entsprechend ablaufen zu lassen.
Bei der Generierung des Quellcodes wird wahlweise C# oder VB.NET erzeugt. Zur Entwurfszeit erkennt SubSonic automatisch die im Projekt verwandte Sprache und generiert entsprechenden Code.
Setup und Configuration
Um SubSonic einsetzen zu können, braucht man zuerst die Subsonic.dll. Diese kann unter http://www.codeplex.com/actionpack heruntergeladen werden. Die SubSonic.dll einfach ins Bin-Verzeichnis kopieren und folgende Anpassungen in der Web.config vornehmen:
<configSections>
<section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic"
allowDefinition="MachineToApplication" restartOnExternalChanges="true"
requirePermission="false"/>
</configSections>
Danach muss der richtige DataProvider eingerichtet werden. Ich beschränke mich der Einfachheit halber auf den SQL Server.
<SubSonicService defaultProvider="SqlDataProvider" spClassName="SPs" fixPluralClassNames="true">
<providers>
<add name="SqlDataProvider" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="NorthwindConnection"/>
</providers>
</SubSonicService>
Natürlich gehört auch eine normale Connectionstring Definition dazu.
<connectionStrings>
<add name="NorthwindConnection" connectionString="Data Source=localhost\SQLExpress; Database=northwind; Integrated Security=true;"/>
</connectionStrings>
Wichtig ist dabei, dass der connectionStringName und der Name im ConnectionSting übereinstimmen.
Als Letztes muss der Buildprovider konfiguriert werden:
<buildProviders>
<add extension=".abp" type="SubSonic.BuildProvider, SubSonic"/>
</buildProviders>
Um dem Buildprovider mitzuteilen für welche Tabellen Objekte erstellt werden sollen, erstellt man eine Textdatei mit dem Namen Builder.abp im App_Code Verzeichnis. Wenn man nur einen * in dieser Datei speichert, werden für alle Tabellen entsprechende Klassen erzeugt. Alternativ kann man aber auch nur einzelne Tabellen nennen. Dann wird die Klassengenerierung auf diese Tabellen beschränkt. Um es hier nochmal zu betonen, der BuildProvider funktioniert nur in einer Fulltrust Umgebung. Läuft das Zielsystem in Mediumtrust sollte man nach der Fertigstellung die Klassen im Source genieren und kompilieren. Für den Produktiveinsatz ist das sowieso die zu empfehlende Vorgehensweise.
Die Bedeutung der einzelnen Tags ist auf der Wiki Seite des Projekts erläutert.
Anwendung
Sobald die Konfiguraton vorgenommen und wurde sowie die Verbindung zur Datenbank steht und die .abp Datei gespeichert wurde, stehen die Datenbankobjekte sofort zur Verfügung. Ich verwende für die Beispiele die allseits beliebte Northwind Datenbank.
Product p = new Product();
p.ProductName = "Testprodukt";
p.Save();
int prodID = p.ProductID;
In VB.NET würde das dann so aussehen:
Dim p As New Product
p.ProductName = "Testprodukt"
p.Save()
Dim prodID As Integer = p.ProductID
Ein Tip hinsichtlich der Benutzung von VB.NET zusammen mit SubSonic. Standardmäßig werden die Klassen in C# erstellt. Damit der Builder weiss, daß er VB Code erzeugen soll müssen Sie ein eine VB Klasse im App_Code Verzeichnis plazieren. Wenn Sie keine weiteren Klassen haben, reicht es auch eine komplett leere class1.vb im Verezichnis zu erzeugen. Eine weitere generelle Voraussetzung damit SubSonic eine Klasse für eine Tabelle erstellt ist das Vorhandensein eines Primary Keys, zusammengesetzte Keys funktionieren leider in der Version 1.0.6 noch nicht.
Das Laden eines Datensatzes geht ähnlich einfach vonstatten wie die Speicherung.
Dim p As New Product
p.LoadByKey(78)
Label1.Text = p.ProductName
Um beispielsweise alle Produkte in einem GridView anzuzeigen benötig man zwei Zeilen Code:
GridView1.DataSource = Product.FetchAll();
GridView1.DataBind();
Um nur eine gefilterte Untermenge abzufragen gibt es folgende Möglichkeit:
GridView1.DataSource = Product.FetchByParameter(Product.Columns.SupplierID,1);
GridView1.DataBind();
Das gibt nur einen ersten Eindruck, welche Möglichkeiten noch in SubSonic stecken. Hierauf kann ich bei entsrpechendem Interesse in einem zweiten Teil eingehen. So kann man über Query Objekte auch deutlich komplexere Abfragen erstellen. Außerdem kann man die einzelnen Klassen natürlich über Partial Classes mit eigener Business-Logik anreichern und erweitern.
Erläuterungen zu allen Eigenschaften und Methoden findet man im Projekt-Wiki außerdem gibt es ein aktives Forum.
Zum Abschluß möchte ich noch ein mitgeiliefertes Control vorstellen, das besonders für die webbasierte Administration von Datenbanktabellen gedacht ist und von Ruby on Rails inspiriert wurde.
Mit den folgenden Zeilen:
<cc1:Scaffold ID="Scaffold1" TableName="Products" runat="server">
</cc1:Scaffold>
wird ein nettes Control gezaubert, das eine komplette Tabelle darstellt:
mit der Möglichkeit Datensätze zu erstellen und zu editieren:
Besonders nett ist in diesem Zusammenhang, daß abhängige Tabellen direkt als Combobox erzeugt werden.
Alles in allem ist SubSonic ein sehr gelungenes Werkzeug um sich eine Menge Tipperei zu ersparen und vor allen Dingen in Proof of Concept oder Rapid Prototyping Phasen schnell präsentable Ergebnis in den Browser zu zaubern.
Wie bereits erwähnt wird das Projekt derzeit lebhaft weiterentwickelt und für Mitter März ist die Version 2.0 angekündigt die einige vielversprechende Erweiterungen mit sich bringen wird (AJAX, Command line Tool um nur einige Beispiele zu nennen).
Donnerstag, 22. Februar 2007 16:22