Der Borland C#Builder wurde vor einigen Monaten in den vier Versionen Personal, Professional, Enterprise und Architect veröffentlicht. Bis auf die Personal Edition enthalten diese alle etwas, was meiner Meinung nach das beste an C#Builder ist, nämlich die so genannten Borland Data Provider for ADO.NET. In diesem Artikel möchte ich zeigen, was genau man mit den BDP for .NET und C#Builder machen kann.
ADO.NET und BDP
Das .NET Framework stellt Datenbank-Konnektivität über ADO.NET zur Verfügung und tatsächlich bieten die meisten Datenbankanbieter heute .NET-Zugriff auf ihre Datenbankprodukte an. Hierfür verwenden sie einen Satz von Klassen, die das ADO.NET Data Provider-Modell implementieren. Entwickler können damit gut arbeiten, da sie nicht den Umgang mit einem anderen Satz von Komponenten lernen müssen, wenn sie mit einer anderen Datenbank arbeiten wollen. Mit dem Release von C#Builder hat Borland eine Datenzugriffs-Technologie namens Borland Data Providers for .NET (bzw. for ADO.NET) eingeführt. Dabei handelt es sich zwar um einen neuen Satz von Komponenten, aber dieser setzt ebenfalls das ADO.NET-Entwurfsmuster um. Er erweitert die grundlegenden ADO.NET-Komponenten um neue Fähigkeiten und Funktionalitäten, sowohl für die Entwurfs- als auch die Laufzeit.
Die Borland Data Provider implementieren und erweitern die ADO.NET Provider-Klassen - genauer die Klassen
SqlConnection,
SqlDataAdapter und
SqlCommand - und sind für verschiedene DBMS wie InterBase, SQL Server 2000 Developer Edition (aka MSDE), SQL Server 2000, Oracle und DB2 verfügbar.
In diesem Artikel möchte ich demonstrieren, wie die BDP for .NET sich zur Entwurfszeit verhalten und die Schritte, die für das Deployment einer mit ihnen erstellten Applikation nötig sind, beschreiben.
Verbindung mit InterBase
Die Borland Data Provider for .NET sind in jeder C#Builder-Version außer der freien Personal Edition verfügbar. C#Builder Professional enthält BDP-Treiber für lokale InterBase- und MSDE-Datenbanken, Enterprise und Architect zusätzliche Treiber für InterBase, SQL Server, Oracle und DB2. In diesem Artikel wollen wir uns mit InterBase verbinden, sodass C#Builder Professional ausreicht, um mitzuspielen.
Beginnen Sie ein neues C#Builder-Projekt und geben Sie diesem einen sinnvollen Namen, etwa
BDPIB. In der rechten oberen Ecke der C#Builder-IDE sehen Sie den Project Manager und direkt darunter drei Register, darunter eines für den Data Explorer (der Name ist einfach Data Explorer und nicht Borland Data Explorer, da dies zu dem unglücklichen Akronym BDE führen würde.).
Der Data Explorer zeigt die verfügbaren BDP-Provider an, die mit der jeweiligen C#Builder-Version installiert sind. Selbstverständlich muss auch die Datenbank, mit der Sie sich verbinden wollen, laufen (also starten Sie entweder InterBase oder lassen Sie diese als NT-Dienst laufen). Sie können den InterBase-Knoten anklicken und öffnen, um die Verbindungen zu sehen. Die Treiber-Einstellungen sind in
bdpDataSources.xml gespeichert, die verschiedenen Verbindungen in
bdpConnections.xml. Beide Dateien befinden sich im Verzeichnis
BDP\1.0\bin directory. Wenn Sie eine neue Verbindung hinzufügen wollen, können Sie mit der rechten Maustaste auf einen Treiber-Knoten klicken und die Option Add new Connection wählen. Um einen neuen Treiber hinzuzufügen (beispielsweise den BDP-Treiber für MySQL, den Sie auf Borlands CodeCentral-Seiten [1] finden), müssen Sie
bdpDataSources.xml jedoch von Hand editieren.
Sie können entweder eine neue Verbindung hinzufügen oder aber die Default-Connection bearbeiten, also die Datenbank und andere Properties anpassen, um korrekt auf InterBase zugreifen zu können. Um die bestehende Verbindung zu editieren, wählen Sie über die rechte Maustaste die Option Modify Connection, wodurch der Connection Editor (siehe Abb. 1) gestartet wird.

Abb. 1: Connections Editor
Neben Username und Passwort ist
Database die wichtigste Eigenschaft. Beachten Sie, dass Sie, wenn Sie von einem anderen Client-Rechner aus auf die InterBase-Datenbank zugreifen wollen, dem Pfad den Namen oder die IP-Adresse des Servers voranstellen müssen (in diesem Fall
192.168.92.42). Dies ist besonders wichtig, wenn man ASP.NET-Anwendungen erstellt.
Sie können den Button Test verwenden, um zu prüfen, ob die Einstellungen korrekt sind, und den Dialog schließen, wenn diese ordnungsgemäß funktionieren. Öffnen Sie dann im Data Explorer den Knoten
IBConn1, um eine Liste der Tabellen, Views und Prozeduren der Beispieldatenbank
employees zu sehen (siehe Abb. 2).

Abb. 2: Die Beispieldatenbank im Data Explorer
Um zu sehen, wie einfach die BDP-Komponenten verwendet werden können, wählen Sie nun die Tabelle
EMPLOYEE aus und ziehen diese auf Ihr Windows Form. Es mag so aussehen, als sei nichts passiert, aber wenn Sie am unteren Rand des Designers schauen, werden Sie sehen, dass zwei nicht sichtbare BDP-Komponenten erzeugt wurden, nämlich
bdpConnection1 und
bdpDataAdapter1. Erstere ist für die Verbindung mit der InterBase-Datenbank verantwortlich, die zweite nutzt diese Verbindung, um mit der
EMPLOYEE-Tabelle zu kommunizieren.
Wir können die Verbindungs-Komponente ignorieren (diese haben wir bereits getestet, als wir den Connections Editor verwendeten) und uns der Konfiguration der
bdpDataAdapter-Komponente zuwenden.
BdpDataAdapter
Wählen Sie die
BdpDataAdapter-Komponente aus. Im unteren Teil des Objekt-Inspektors sehen Sie zwei spezielle Entwurfszeitunterstützungs-Funktionen (Verbs), nämlich
Configure Data Adapter... und
Generate Typed Dataset.... Wenn Sie erstere anklicken, wird der in Abbildung 3 gezeigte Data Adapter Configuration-Wizard angezeigt.

Abb. 3: Der Data Adapter Configuration-Wizard
Beim Start zeigt der Wizard den Namen der Tabelle, die Sie aus dem Data Explorer gezogen haben. Jetzt können Sie die Tabelle jedoch wechseln und die Felder angeben, die Sie auswählen, einfügen, löschen oder aktualisieren wollen. Wenn Sie eine neue Tabelle auswählen, bekommen Sie auch eine neue Liste mit Feldern für diese Tabelle angezeigt. Sie können angeben, ob Sie nur Daten auswählen wollen (für read-only Applikationen) oder auch Inserts, Deletes und/oder Updates zulassen wollen. Den generate SQL-Button müssen Sie offensichtlich betätigen, um die neuen SQL-Anfragen, die die
BdpDataAdapter-Komponente verwendet, zu generieren.
Die Checkbox
Optimize (per Default nicht aktiviert) kann verwendet werden, um Queries zu erzeugen, die nur die primären Index-Felder in der
where-Klausel verwenden. Dies führt zu effizienteren Anfragen, kann aber zu Problemen führen, wenn zwei oder mehr User Nicht-Schlüsselfelder des selben Datensatzes aktualisieren.
Wie dem auch immer, selbst wenn Sie die Tabelle nicht wechseln und die Felder auf
* belassen, so führt ein Klick auf Generate SQL zu einer Anfrage, die alle Felder explizit auflistet:
SELECT EMP_NO, FIRST_NAME, LAST_NAME, PHONE_EXT, HIRE_DATE, DEPT_NO, JOB_CODE, JOB_GRADE, JOB_COUNTRY, SALARY FROM EMPLOYEE
Wenn Sie die SQL-Statements erzeugt haben, können Sie über das Register
DataSet angeben, welches DataSet verwendet werden soll, um das Ergebnis des SQL-Befehls aufzunehmen. Da noch keine DataSet-Komponente existiert, sollten wir die Option, ein neues DataSet zu erstellen, wählen und dieses zum Beispiel
dataSet1 nennen (siehe Abb. 4).

Abb. 4: Neues DataSet anlegen
Nachdem wir ein DataSet spezifiziert haben, können wir zum Register
Preview gehen und uns das Ergebnis anschauen (siehe Abb. 5). Die Option
Limit rows hat dabei übrigens ausschließlich Auswirkungen auf die Wiedergabe im Preview-Dialog, nicht auf die Darstellung der Daten zur Laufzeit.

Abb. 5: Vorschau auf die Daten
Wenn Sie den Data Adapter Configuration-Dialog schließen, werden Sie sich vielleicht fragen, warum Sie die DataSet-Komponente nicht im Bereich für nicht sichtbare Komponenten im Designer sehen. Dies ist aber nur ein kleines Entwurfszeit-Problem: Wählen Sie über die rechte Maustaste Line up Icons und die Komponente wird sich zeigen.
Wir haben bislang zwei der vier Borland Data Provider-Komponenten verwendet
BdpConnection und
BdpDataAdapter. Bleiben also die Komponenten
BdpCommand und
BdpCommandBuilder.
Betrachten von Daten
BdpDataAdapter nutzt
BdpCommand, um das DataSet mit dem Ergebnis der SQL-Anfrage zu befüllen. Wir können die resultierenden Daten visualisieren, indem wir visuelle Komponenten wie das DataGrid oder andere Klassen, die Listen unterstützen, einsetzen.
Ziehen Sie aus der Kategorie
Data Controls eine DataGrid-Komponente auf das Formular. Setzten Sie die Eigenschaft
DataSource auf
dataSet1 und öffnen Sie dann die Eigenschaft
DataMember, um die richtigen Daten auszuwählen. Anfangs gibt es vielleicht noch nichts für das
DataMember auszuwählen. Wenn Sie jedoch die Eigenschaft
Active des
BdpDataAdapters auf
True setzen, wird das DataSet mit den in
Table1 enthaltenen Daten gefüllt. Und das beste daran: Sie werden die Daten live zur Entwurfszeit sehen (siehe Abb. 6).

Abb. 6: Live Data
Daten aktualisieren
Natürlich wollen wir unsere Daten nicht nur betrachten, sondern dem Anwender auch erlauben, diese zu verändern - und diese Änderungen gegebenenfalls wieder rückgängig zu machen. Letzteres ist zum Glück sehr einfach, da ADO.NET (und BDP) auf dem Konzept eines entkoppelten DataSets basiert. Das heißt, dass Änderungen, die wir an den Daten im DataGrid durchführen, nicht automatisch an die InterBase-Datenbank selbst zurückgeschickt werden. Die Änderungen werden im DataSet gecacht und wir müssen sie explizit an die Datenbank senden - oder sie aber vorher wieder rückgängig machen.
Fangen wir mit dem Undo an: Die DataSet-Komponente verfügt über eine nette Methode namens
RejectChanges. Diese nimmt alle Änderungen zurück, die gemacht wurden, seitdem das letzten Update an die InterBase-Datenbank geschickt wurde. Platzieren Sie drei Buttons auf dem Formular, nennen Sie diese
btnUndo,
btnUpdate und
btnClose und setzen Sie deren
Text-Eigenschaft auf
Undo,
Update und
Close. Schreiben Sie in den
Click-Event Handler für das Undo folgenden Code:
private void btnUndo_Click(object sender, System.EventArgs e)
{
dataSet1.RejectChanges();
}
Jetzt stellt sich natürlich die Frage, wie wir Updates an die Datenbank schicken können. Dies lässt sich ebenfalls mit einer Zeile Code bewerkstelligen, indem wir die Methode
AutoUpdate aufrufen. Dies kann im
Click-Event des
Update-Buttons implementiert werden:
private void btnUpdate_Click(object sender, System.EventArgs e)
{
if (this.dataSet1.HasChanges())
this.bdpDataAdapter1.AutoUpdate();
}
Beachten Sie, dass die
HasChanges-Methode dabei hilft zu entscheiden, ob es überhaupt sinnvoll ist,
AutoUpdate (oder
RejectChanges) aufzurufen.
Schließlich ist es noch eine gute Idee zu überprüfen, ob irgendwelche Änderungen vorliegen, bevor man die Anwendung beendet. Dies lässt sich im
Click-Ereignis des
Close-Buttons erledigen:
private void btnClose_Click(object sender, System.EventArgs e)
{
btnUpdate_Click(sender, e);
Close();
}
BdpCommandBuilder
Es ist toll, wenn man alles in einer einzigen Zeile Code machen kann. Um die Verwendung der
BdpCommandBuilder-Komponente zu illustrieren, wollen wir jedoch die
AutoUpdate-Methode mit etwas mehr Details neu schreiben.
Ich erzeuge dazu eine
BdpCommandBuilder-Instanz und setzte den
UpdateMode auf
All (dies platziert alle Felder in die
where-Klausel des
Update-SQL-Statements; die Alternative wäre
Key, womit nur die Primärschlüssel-Felder in die
where-Klausel gesetzt würden). Dann rufe ich explizit die
Update-Methode auf und übergebe das DataSet sowie den Namen der zu aktualisierenden Tabelle. Der
BdpCommandBuilder generiert nun eine SQL-Anfrage, um die Updates an die InterBase-Datenbank zu schicken. Daraus resultiert die in Listing 1 gezeigte Implementierung des
Click-Events des
Update-Buttons (inklusive
try-
catch-Block).
Listing 1 private void btnUpdate_Click(object sender, System.EventArgs e)
{
if (this.dataSet1.HasChanges())
{
BdpCommandBuilder cb = new BdpCommandBuilder(bdpDataAdapter1);
try
{
cb.UpdateMode = Borland.Data.Common.BdpUpdateMode.All; // or Key
bdpDataAdapter1.Update(dataSet1, "Table1");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}

Abb. 7: Unsere Applikation zur Laufzeit
Deployment der Applikation
Um die ausführbare Datei unserer C#Builder-Applikation deployen zu können, muss auf dem Client-Rechner zunächst der InterBase-Client (vor allem
gds32.dll) installiert sein. Danach folgen die C#Builder Executable selbst und die Borland Database Provider-Assemblies. Letzere sind von Borland mit einem Strong Key signiert, sodass sie mit gacutil in den Global Assembly Cache (GAC) deployt werden können.
Folgende BDP-Assemblies müssen deployt werden:
- Borland.Data.Provider.dll: die Borland Data Provider for .NET
- Borland.Data.Common.dll: gemeinsame BDP-Klassen
- Borland.Data.Intervase.dll: InterBase-spezifische Klassen
- bdpint.dll: die Win32-DLL, die auf den gdb32.dll-InterBase-Client linkt
Bob Swart (aka Dr. Bob) arbeitet als Autor, Trainer, Webmaster, Entwickler und Consultant. Er ist erreichbar unter www.drbob42.com/.Links und Literatur