Seit einer langen Zeit liegt der Begriff Impedance Mismatch oft wie ein schwerer Fluch über dem Wunsch der Anwender, der Persistenz von Objekten etwas eleganter Herr zu werden. So werden zwar die Mapping-Lösungen immer ausgefeilter, aber grundlegende Konzepte wie Vererbung, Polymorphie, komplexe Referenzen etc. sträuben sich recht erfolgreich, sich dem OO-relationalen Mapping hinzugeben. Nicht triviale Objekte direkt zu speichern erscheint daher als der sinnvollste Weg. Er hat sich jedoch bisher in Ermangelung vernünftiger Standards und einfacher bzw. leistungsfähiger Tools leider noch immer nicht als erfolgreicher Weg herausgestellt. Dem begegnet db4o, indem die Datenbank zusätzlich ein weiteres Persistenzproblem angeht: Eine Abfragesprache weniger anzubieten. db4o wird unter einem „Dual Licence Model“ vertrieben – die Verwendung ist so lange frei, wie db4o nicht in einem Non-GPL-Produkt eingebettet und vertrieben wird.
Von 0 auf 100 in wenigen Sekunden
Bevor die brandneuen Features von db4o vorgestellt werden, soll dem Leser die Möglichkeit gegeben werden, sich innerhalb weniger Minuten selbst ein Bild von der Objektdatenbank mit ihren gerade für erfahrenen Entwickler neuartigen Konzepten zu machen. Sie kann von db4o.com schnell in der passenden .NET- oder Java-Version heruntergeladen werden. Nach der Installation des MSI-Archives liegt eine Assembly mit dem Namen db4o.dll vor, auf der zu jedem Projekt ein Verweis eingefügt wird. Jetzt kann jede beliebige Klasse mit nur zwei Zeilen gespeichert werden. Schon hier könnten manche Leser stutzig werden: Keine besonderen Ableitungen, keine Interfaces, unter modernen Plattformen auch keine besonderen Konstruktoren? Das klingt verdächtig, aber es funktioniert. Jetzt also eine Objektinstanz speichern:ObjectContainer db = Db4o.OpenFile("C:/tmp/myDB.yap");db.Set(new Person("John", 42));db.Commit() ;db.Close();
Listing 1------------------------------------------------------------------ObjectContainer db = Db4o.OpenFile("C:/tmp/myDB.yap");Person tmp = new Person();tmp.name = "John";ObjectSet res = db.Get(tmp);p1 = (Person) res.Next(); // Print p2p1.Age = 43 ;db.Set(p1); // update the objectdb.Delete(p1); //delete the objectdb.Commit();db.Close();
Eine Abfragesprache weniger?
Grundsätzlich sind alle Abfragesprachen (Query Languages) wie SQL, OQL etc. immer noch mehr oder weniger String- basiert. Und in vielen Fällen ist eine String-basierte Abfragesprache durchaus von Vorteil. Viele Entwickler beherrschen SQL, es gibt „Legacy Code“ und SQL (als populäre Datenbanksprache) enthält viele nützliche Konstrukte. Aber es kann durchaus sehr viele Fälle geben, in denen SQL oder andere String-basierte Abfragesprachen problematisch sind. db4o ist daher die erste Datenbank, die einem Forschungsansatz von William Cook folgt [2][3] (Abbildung 1), bei dem einfach die eigene Programmiersprache als Abfragesprache vorgeschlagen wird. Die Idee besteht darin, die Mächtigkeit von C# oder Java auszunutzen, um quasi ein einfaches Abfrageobjekt zu erstellen, das das Ergebnis der Abfrage in einer typischen Liste zurückliefert. Diese Abfragen in der hauseigenen Programmiersprache werden hier Native Queries (NQ) genannt. Ein einfaches Beispiel:IList <Pilot> pilots = db.Query <Pilot> (delegate(Person person) {return person.Age > 50 && person.Name == "John";});
- Diese Abfragen sind typsicher. Der gesamte Code in dieser Abfrage wird in der IDE zur Entwicklungszeit geprüft. Fehler, die sonst in SQL-Strings verborgen wären und dort erst spät gefunden würden, werden in der Entwicklungsumgebung (Visual Studio) sofort entdeckt.
- Der Code ist refaktorierbar. Das Schlagwort Refactoring – quasi Code- oder Architekturanpassungen, Änderungen oder Verbesserungen – ist in aller Munde und auch in alle guten Entwicklungsumgebungen integriert. Selbst einfache Refactorings wie das Umbenennen von Feldern kann bei RDBMS/Mapping-Lösungen zu unangenehmen Fehlern führen, da sie in den Mapping-XML- Dateien oder im SQL-Code nicht direkt abhängig sind. Das Refactoring eines Feldes einer C#-Klasse allerdings bewirkt, dass die Abfrage selbst auch sofort korrekt geändert wird.
- Der Entwickler braucht keine weite re Abfragesprache mehr, außer seiner (Lieblings-) Sprache selbst. Er kann beliebige AND-, OR- oder NOT-Sprachelemente von C# nutzen.
Komplexität beherrschen
Objektdatenbanken spielen ihren Vorteil – auch in Bezug auf die Performance – besonders bei komplexen Objektstrukturen aus. So gibt es durchaus viele Anwendungen, deren Objektstruktur tief ist, was häufiger bei baum- oder netzartigen Strukturen der Fall ist. In der Industrie sind hier nicht selten Objekttiefen von 10 bis 20 anzutreffen (Firma referenziert Angestellte, Angestellte referenziert Personen, Personen referenziert Adressen, usw.).Aber auch dies soll an einem einfachen Beispiel in Abbildung 2 illustriert werden: Gegeben sei eine Klasse Part, die ein beliebiges Bauteil referenziert. Diese wird um eine umfassende Klasse PartAssembly erweitert (Listing 2), die eine ArrayListe der Bauteile enthält. Das Ergebnis kann zum Bespiel ein Auto oder ein Mainboard repräsentieren.
Listing 2------------------------------------------------------public class Part {private string category;private string name;private string manufacturer;private string manufacturerPartNumber;. . .}public class PartAssembly : Part {private System.Collections.ArrayList components;. . .}
db4o speichert jedes beliebige Objekt als ein solches über db.set(anyObject) ab. Das Suchen und Laden dieser Objekte ist ebenso trivial, dank der Abfragesprachen QBE, SODA und den neuen NQs. Ein Zusammensetzen von komplexen Objekten aus einer Vielzahl von relationalen Tabellen kann daher völlig entfallen. Listing 3 und 4 zeigen das Speichern eines Bauteiles und (QBE) Suchen nach Bauteilen, die einem konkreten Hersteller (Manufacturer) entsprechen.
Listing 3-------------------------------------------------------------ObjectContainer Database = Db4o.OpenFile(fileName);// Container öffnen// Erstelle ein neues Part ObjektPart mb = new Part ( "Motherboard","Desktop Board D945Gnt","Intel","BOXD945GNT");Database.Set(mb); // Speichere das Bauteil in der DatenbankDatabase.Commit();// Schliesse die Transaktion abDatabase.Close(); // Schliesse die Datenbank
Listing 4------------------------------------------------------------------------------------Part PartTemplate = new Part(// erstelle ein Template-Objekt zum Suchennull,"Desktop Board D945GNT",null, null);ObjectSet result = Database.Get(PartTemp);// Suche nach Objekten die passenif(Result.HasNext()) { // Auslesen der ObjektePart mb = (Part) result.Next();// Etwas mit dem Objekt machen. . .}
Db4o.configure().activationDepth(5);// Hier z.B. 5 Stufen tief
Fazit
Der Native-Query-Ansatz ist ein Leckerbissen für Entwickler, der mit Sicherheit den bisherigen Verfahren/Abfragesprachen erhebliche Marktanteile streitig machen wird. Seine Berechtigung erfahren NQs alleine schon dadurch, dass Microsoft im Rahmen seines LINQ-Projektes [4] diesen Trend erkannt hat und selbst vorantreibt. So wird die LINQ-Syntax ein Teil des kommenden C# 3.0 sein. Durch die vorgestellten Mechanismen und Vereinfachungen bei der Persistenz könnten Objektdatenbanken durchaus einen zweiten Frühling erleben. Insbesondere in Nischen, die nicht durch RDBMS-Lösungen oder Data-Warehouse-Anforderungen besetzt sind. Zum Beispiel im mobilen und Embedded-Bereich, der durch die nur 400 KB große DLL ideal für db4o erscheint. Der Leser sei daher herzlich eingeladen, die paar Minuten zu investieren, um diese Technologie einem Praxistest zu unterziehen.- Native Queries
- Unterstützung für .NET 2.0 Generic Collection
- Strong Encryption für db4o File I/O
- Ein Hardware-Crash-Simulator
- Ein neues Freespace-Management-System
Features, die 2006 kommen:
- RDBMS-Replikation mittels Hibernate
- Transparente Aktivierung von Objekten
- Neuer Objectmanager V2.0
- Schnelle Collections
- Ein Visual-Basic-Tutorial
- Verbesserte Defragmentierung
- J2ME-CLDC/MIDP-Unterstützung
Links & Literatur
- www.polepos.org
- William R. Cook, Siddhartha Rai: Statically Typed Objects as Remotely Executable Queries, Dept of CS, University of Texas at Austin
- William R. Cook, Carl Rosenberger: Native Queries for Persistent Objects A Design White Paper, August 2005
- msdn.microsoft.com/netframework/future/linq/




