Freitag, 29. August 2008

entwickler.com Magazine Konferenzen Akademie Entwickler-Forum Jobbörse Bücher
Software & Support Verlag




April 2006
aus Der Entwickler Ausgabe: 1.2004
Beschaffungslösung
C#Builder und die Borland Data Providers for ADO.NET
von Bob Swart

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


    Hat Ihnen dieser Artikel gefallen? Dann abonnieren Sie das Entwickler Magazin direkt über unser Online-Formular.



zur vorherigen Seite
zurück
an den Anfang der Seite
nach oben
Diesen Artikel drucken
drucken
Diesen Artikel weiterempfehlen
empfehlen
Software & Support Verlag GmbH