Das .NET Datenbanken How To

v o n B e r n d Q u a m b u s c h
Stand : 11.04.2012


Inhaltsverzeichnis :

1. Vorwort
2. ADO.NET und Client/Server
3. Systemvoraussetzungen
4. Die erste Verbindung zur Datenbank
5. Daten lesen
6. Daten ändern
7. Daten einfügen
8. SQL-Kommando ausführen
9. SQL Compact und MySQL
10. Wahl der Datenbank
11. Datenbankunabhängige Programmierung
12. O/R-Mapper
13. Eine fertige Applikation

 

1. Vorwort

Der Zugriff auf Datenbanken ist eine der Hauptanwendungen vieler .NET-Programme. Mit ADO.NET bietet das Framework zahlreiche Möglichkeiten hierfür, leider ist es auch sehr umfangreich und deshalb für den Anfänger etwas unübersichtlich.

Dementsprechend oft werden Fragen zu Datenbanken und Datenbankzugriffen im Forum gestellt. Da die Fragen sich wiederholen und ich mich inzwischen mit vielen Datenbanken beschäftigt habe, möchte ich hier meine Erfahrungen mitteilen und viele der Fragen zu Datenbanken beantworten.

Dokumentation zu ADO.NET gibt es genug, sogar ganze Bücher : "Datenbankprogrammierung mit C#" (kann ich sehr empfehlen). Viele C#-Anfänger wollen sich aber nicht die Zeit nehmen ein ganzes Buch durchzuarbeiten. Ich schreibe den folgenden Text deshalb so, dass man schnell zu einem Erfolg kommt. Die Beispiele sind alle sofort lauffähig. Später kann sich der Leser ja dann mit Büchern (Online und Offline) weiter in die Materie einarbeiten.

Deshalb ist das Vorwort jetzt auch zu Ende und nach kurzer Erklärung von ADO.NET und den Systemvoraussetzungen (muß beides sein!) geht es dann gleich zum ersten Programmbeispiel mit Erfolgsgarantie.


2. ADO.NET und Client/Server

Mit dem .NET Framework hat Microsoft auch eine völlig neue Technik vorgestellt, um auf Datenbanken zuzugreifen, das sogenannte ADO.NET (Active Data Objects .NET). ADO.NET ist zwar der Nachfolger von ADO, hat aber mit dieser Technologie nichts gemeinsam. ADO.NET wurde so entwickelt, dass es sowohl für Windowsanwendungen auf einem Rechner als auch in grossen Netzwerken und im Internet (viele User greifen auf eine Datenbank zu) benutzt werden kann. Kernstück der ADO.NET-Technologie ist das Dataset. Mehr dazu später.

Die hier benutzen Datenbankserver arbeiten in der Client/Server-Technologie. Dabei wird vom Client-Rechner nicht direkt auf die Datenbankdatei zugegriffen (wie früher bei dBase), sondern der Client kommuniziert über ein Protokoll (TCP/IP) mit dem Datenbankserver. Der Datenbankserver ist eine Software, die auf dem Server-Rechner installiert ist, z.B. der Microsoft SQL Server Express Edition.
Der Client hat nie direkten Zugriff auf die Datendateien, er braucht nicht mal zu wissen wo die sich befinden (Eine Ausnahme sind die sogegannten Embedded Datenbankserver für Einzelplatzbetrieb).
Durch die Client/Server-Technologie erreicht man höhere Sicherheit und höhere Geschwindigkeit.
Ich schreibe das an dieser Stelle weil immer wieder Beginner in der Datenbankprogrammierung versuchen, direkt auf irgendwelche Datendateien zuzugreifen. Das ist nicht notwendig, sondern sogar gefährlich.

ADO.NET arbeitet verbindungslos, jedenfalls die meiste Zeit. Eine Connection zur Datenbank wird immer nur kurz aufgebaut, Aktionen werden durchgeführt und dann wird die Verbindung wieder geschlossen. So können auf einem Webserver viele Tausend User auf eine Datenbank zugreifen ohne dass zuviele Resourcen verbraucht werden.


3. Systemvoraussetzungen

Die Beispiele hier wurden im Visual Studio 2008 Professional mit dem .NET Framework 2.0 auf Windows XP und Windows Vista erstellt. Sie sollten aber auch mit dem kostenlosen Visual Studio Express und Visual Studio 2005 laufen. Wer noch das Framework 1.1 einsetzt sollte schnellstens auf 2.0 oder höher upgraden, denn das bietet wirklich viele sinnvolle neue Funktionen, auch unter ADO.NET.

Die Beispiel sind immer doppelt vorhanden, einmal für den Microsoft SQL Server Express Edition und einmal für den Microsoft SQL Server Compact Edition. Mit einer dieser Datenbanken sollte man auch anfangen. Die Express Edition wenn es größere Datenmengen sind oder wenn mehrere Anwender auf die gleichen Daten zugreifen sollen, die Compact Edition wenn es eine Einzelplatzanwendung werden soll mit kleinen Datenmengen, die man dann auch einfach an andere Leute weitergeben kann.

Die genauen Unterschiede sind im Kapitel 9 und 10 erklärt.

Wenn die Daten bereits in einer Datenbank vorliegen so kann man natürlich auch mit MySQL, Oracle oder SQLite beginnen, die Beispiele lassen sich einfach anpassen.


4. Die erste Verbindung zur Datenbank

So, nun genug geredet, jetzt gehts los : Die erste Verbindung zur Datenbank wird aufgebaut. Das ist schon die erste Hürde, zu der es zahlreiche Fragen in den verschiedenen Foren gibt. Man möge nur einmal das Word "Connectionstring" in die Suche eingeben !

Die erste Verbindung zur Datenbank stellen wir nicht mit einem Programm her, sondern immer mit dem SQL Server Management Studio Express. Das ist beim SQL Server Express Edition mit Advanced Services dabei oder kann einzeln bei Microsoft heruntergeladen werden. Bitte unbedingt die neueste Version nehmen !

Bei Einsatz von MySQL für den ersten Kontakt zur Datenbank den MySQL Query Browser verwenden, bei Oracle die Webclient-Oberfläche, bei PostgreSQL den pgAdmin III.

Nun die Beschreibung für die Microsoft SQL Server :
Das SQL Server Management Studio Express starten mit [Start] [Programme] [Microsoft SQL Server 2005] [SQL Server Management Studio Express]
Es öffnet sich ein Dialog, diesen wie folgt ausfüllen :
Servertyp :  "Datenbankmodul" angeben für den SQL Server Express oder ".." für SQL Server Compact.
Servername : Servername oder Server-IP-Nummer angeben.
Authentifizierung : SQL-Server-Authentifizierung
Anmeldename : sa
Kennwort : Das bei der Installation vergebene Kennwort eingeben.
Mit [Verbinden] wird nun eine Verbindung zum SQL-Server oder zu der Compact Server Datei hergestellt.

Nun die zweite Verbindung mit einem eigenen Programm : Damit ich mich mit einem .NET Programm mit einer Datenbank verbinden kann benötige ich eine Datenbank-Connection. Diese ist speziell für den jeweiligen Datenbanktyp, also z.B. SqlConnection für Microsoft SQL Server.

Hier der Programmcode für unseren ersten selbstprogrammierten Kontakt zur Datenbank, hier für den SQL Server Express :

using System.Data;
using System.Data.SqlClient; private void button1_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false"; SqlConnection conn = new SqlConnection(connstr); conn.Open(); string version = conn.ServerVersion; conn.Close(); MessageBox.Show("Serverversion : " + version); }

Beim conn.Open und beim conn.ServerVersion kann ein Fehler auftreten, wenn nämlich der Datenbankserver nicht antwortet oder die Versionsinfo nicht abrufbar ist. Deshalb Datenbankoperationen immer in einen Try-Block einbauen.

Das conn.Close muss dann nach dem Try-Catch kommen, denn die Verbindung sollte auf jeden Fall geschlossen werden. Auch ohne eine aktive Verbindung schadet ein conn.Close nie !

Nun unser Programm für den SQL Server Express, mit Fehlerbehandlung :

using System.Data;
using System.Data.SqlClient; private void button1_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false"; SqlConnection conn = new SqlConnection(connstr); string version = "---Unbekannt---"; try { conn.Open(); version = conn.ServerVersion; } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show("Serverversion : " + version); }

Wichtig : Das conn.Close() nie vergessen, es werden sonst unnötig Resourcen verbraucht. Zwischen dem conn.Open() und dem conn.Close() möglichst wenig Befehle, eine Verbindung sollte immer nur ganz kurz geöffnet bleiben. Man braucht sich keine Sorge zu machen, dass ein dauerndes Öffnen und Schließen von Connections das Programm langsam macht, denn ADO.NET optimiert das Open und Close über Connection Pooling.

 

5. Daten lesen

ADO.NET stellt zwei verschiedenen Möglichkeiten zur Verfügung, um auf Daten in einer Datenbank zuzugreifen : DataReader und DataSet.
Der DataReader kann nur Daten lesen, das dafür aber recht schnell. Einen Datareader öffnet man, liest dann nacheinander einen oder mehrere Datensätze und schliesst den Datareader wieder.

Das sieht so aus :

using System.Data;
using System.Data.SqlClient; private void button3_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false;initial catalog=Northwind"; SqlConnection conn = new SqlConnection(connstr); SqlCommand cmd = new SqlCommand("select top 10 * from Customers", conn); SqlDataReader dr; string meldung = ""; try { conn.Open(); dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); while (dr.Read()) { meldung += dr["companyname"].ToString() + ", " + dr["city"].ToString() + ", "
+ dr["country"].ToString() + "\r\n"; } } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show(meldung); }

 
Einschränkungen des DataReaders : Er kann die Datensätze nur nacheinander lesen, "Vorheriger" oder "Letzter Lesen" gibt es nicht. Die Gesamtzahl der Datensätze kann nicht ermittelt werden bevor alle Datensätze gelesen wurden. Es können nicht zwei DataReader gleichzeitig geöffnet sein (ausser beim SLQ Server 2005 und 2008).

Tipp : Wenn man die Anzahl der Datensätze braucht, um z.B. eine Progressbar von 0 bis 100% anzuzeigen, dann vorher das Kommando 'select count(*) from table1 where ...' ausführen.


6. Daten ändern

Natürlich möchte man Daten in einer Datenbank nicht nur lesen, sondern auch ändern. In diesem Falle verwendet man das sogenannte DataSet, Das DataSet ist ein Container für verschiedene Daten und Tabellen. Es ist erstmal nicht an eine bestimme Datenbank gebunden und kann eigentlich auch ohne Datenbank benutzt werden.

Das DataSet enthält eine oder mehrere DataTable (Tabellen), die wiederum eine oder mehrere DataRows (Zeilen) enthalten können (oder keine). Ein DataSet kann man wie eine kleine Datenbank im Arbeitsspeicher betrachten. Man könnte natürlich eine komplette Datenbank in eine DataSet laden, dann einige Daten verändern und dann zurückspeichern. Aus Geschwindigkeitsgründen und Resourcenverbrauch sollte man das aber unterlassen.

Ein Dataset wird mit "new" angelegt, es kann dann mit dem Befehl ds.Fill() aus einer Datenbank gefüllt werden. Dazu benötigen wir wieder einen DataAdapter und eine DataConnection :

So kann man z.B. auf einzelne Elemente des DataSet zugreifen :

ds.Tables.Count : Anzahl Tabellen
ds.Tables["table1"].Columns.Count : Anzahl Spalten der Tabelle "table1"
ds.Tables["table1"].Rows.Count : Anzahl Zeilen der Tabelle "table1"
ds.Tables["table1"].Columns[0].Columnname : Name der ersten Spalte der Tabelle "table1"
ds.Tables["table1"].Rows[0] : Erste Zeile der Tabelle "table1"
ds.Tables["table1"].Rows[0][0] : Erstes Feld der ersten Zeile der Tabelle "table1"
ds.Tables[0].Rows[0]["Name"] : Feld "Name" in der ersten Zeile der ersten Tabelle

Die Angaben in den eckigen Klammern können Zahlen oder Buchstaben sein, wobei 0 immer das erste Element ist. Bei Zugriff auf ein Feld erhält man erstmal ein Objekt. Wenn ich dieses weiterverarbeiten möchte muss ich es erst in den entsprechenden Typ casten :

string name = (string)ds.Tables[0].Rows[0]["Name"];
int nummer = (int)ds.Tables[0].Rows[0]["Adressnummer"];

Leider erhält man bei falschem Typ oder bei falschen Namen erst zur Laufzeit eine Fehlermeldung.

Um mehrere Zeilen einer Tabelle durchzugehen kann man mit foreach iterieren : foreach (Datarow rw in ds.Tables[0].Rows) ...

Jetzt der komplette Code um ein paar Daten in der Datenbank zu ändern :

using System.Data;

using System.Data.SqlClient; private void button5_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false;initial catalog=Northwind"; SqlConnection conn = new SqlConnection(connstr); SqlCommand cmd = new SqlCommand("select * from Customers", conn); SqlDataAdapter da = new SqlDataAdapter(cmd); SqlCommandBuilder cb = new SqlCommandBuilder(da); DataSet ds = new DataSet(); int anzahl = 0; try { conn.Open(); anzahl = da.Fill(ds, "Customers"); } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show(anzahl + " Zeile(n) gelesen ");
if (anzahl > 0) ds.Tables["Customers"].Rows[0]["Phone"] = "089/12345"; // Telefonnr. des 1. Kunden foreach (DataRow rw in ds.Tables["Customers"].Rows) // in einige Städte 'Deutschland' eintragen. if ((string)rw["City"] == "Münster") rw["Country"] = "Deutschland"; try { conn.Open(); anzahl = da.Update(ds, "Customers"); } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show(anzahl + " Zeile(n) geändert "); }



7. Daten einfügen

Das Einfügen von Daten geht fast genauso (einfach) : 

using System.Data;

using System.Data.SqlClient; private void button6_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false;initial catalog=Northwind"; SqlConnection conn = new SqlConnection(connstr); SqlCommand cmd = new SqlCommand("select * from Customers where 0=1", conn); SqlDataAdapter da = new SqlDataAdapter(cmd); SqlCommandBuilder cb = new SqlCommandBuilder(da); DataSet ds = new DataSet(); int anzahl = 0; try { conn.Open(); da.Fill(ds, "Customers"); } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); DataRow rw = ds.Tables["Customers"].NewRow(); rw["CustomerID"] = 10000; rw["CompanyName"] = "Hampel&Pampel"; rw["ContactName"] = "Hans Hampel"; rw["City"] = "Frankfurt"; rw["PostalCode"] = "60311"; rw["Country"] = "Deutschland"; rw["Phone"] = "069/12345"; ds.Tables["Customers"].Rows.Add(rw); try { conn.Open(); anzahl = da.Update(ds, "Customers"); } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show(anzahl + " Zeile(n) eingefügt.");

 

8. SQL-Kommando ausführen

Man kann natürlich auch direkt ein SQL-Kommando ausführen.

So kann man mit 'create' Datenbanken, Tabellen oder Felder anlegen und ändern.

Mit 'backup' kann man eine komplette Datenbank im laufenden Betrieb sichern (MS SQL Server).

Man braucht dazu eine Connection, ein Command, einen DataAdapter und manchmal einen DataReader.
Es stehen folgende Befehle zur Verfügung um ein Kommando auszuführen :

int anzahl = cmd.ExecuteNonQuery();          // Gibt eine ganze Zahl als Ergebnis zurück, z.B. Anzahl Zeilen nach Update, Insert oder Delete Befehlen
SqlDataReader dr = cmd.ExecuteReader();    // Gibt einen DataReader mit einem oder mehreren Werten zurück
int wert = cmd.ExecuteScalar();    // Gibt den ersten Wert zurück, auch wenn das Ergebnis aus mehreren Werten besteht
 
Beispiel :

using System.Data;

using System.Data.SqlClient; private void button2_Click(object sender, EventArgs e) { string connstr = "data source=localhost\SQLEXPRESS;user id=sa;password=geheim;integrated security=false;"
+ "persist security info=false;initial catalog=Northwind"; SqlConnection conn = new SqlConnection(connstr); SqlCommand cmd = new SqlCommand("update Customers set Country = 'Deutschland' where city = 'München' or city = 'Berlin'", conn); SqlDataAdapter da = new SqlDataAdapter(cmd); int anzahl = 0; try { conn.Open(); anzahl = cmd.ExecuteNonQuery(); } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show(anzahl + " Zeile(n) geändert "); }

 

9. Zugriff auf SQL Compact und MySQL

SQL Compact ist ein kleiner Datenbankserver vom Microsoft, der keine eigene Installation braucht. Für Einzelplatzanwendungen mit kleinen Datenmengen (< 1GB) ist er sehr gut geeignet.

MySQL ist eine bekannte Datenbank aus der Linux-Ecke und wird oft auf Webservern eingesetzt.

Um diese Datenbanken einzusetzen muss man erstmal die entsprechenden Dot.NET Treiber herunterladen und installieren

Download MySQL Connector / Net 5.1 : http://dev.mysql.com/downloads/connector/net/5.1.html

Download SQL Compact : http://www.microsoft.com/sql/editions/compact/default.mspx

Die notwendige DLL's einfach ins Applikationsverzeichnis kopieren, das ist bei MySQL die MySql.Data.dll und bei SQP Server Compact die Dateien System.Data.SqlServerCe.dll, System.Data.SqlServerCe.Entity.dll und sqlce*.dll. Im Project die System.Data-DLL's als Verweis hinzufügen : Projekt / Verweis hinzufügen / Durchsuchen / MySql.Data.dll bzw. System.Data.SqlServerCe.dll auswählen.

Wenn man seine Applikation weitergibt muss man nur die DLL's mitliefern. Eine eigene Installation der Dot.Net Treiber ist nicht notwendig.

Weitere Installationen, wie auf den Homepages der Hersteller angegeben, sind nicht notwendig. Sie sind nur für Integration der Datenbank in die IDE, das brauchen wir aber hier nicht (braucht das überhaupt jemand ?)

Im Programm kann man nun den Namespace angeben und so ganz einfach auf die Datenbank zugreifen :

// MySQL
using System.Data;
using MySql.Data.MySqlClient;
private void button1_Click(object sender, EventArgs e) { string connstr = "data source=192.168.1.1;user id=quasar3;password=quasar3;pooling=false;initial catalog=quasar3";
MySqlConnection conn = new MySqlConnection(connstr); string version = "---Unbekannt---"; try { conn.Open(); version = conn.ServerVersion; } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show("Serverversion : " + version); }


// SQL Compact Edition
using System.Data;
using System.Data.SqlServerCe;
private void button1_Click(object sender, EventArgs e) { string connstr = "Data Source='quasar3.sdf';Default Lock Timeout=60000";
SqlCeConnection conn = new SqlCeConnection(connstr); string version = "---Unbekannt---"; try { conn.Open(); version = conn.ServerVersion; } catch (Exception ex) { MessageBox.Show("Es ist ein Fehler aufgetreten : " + ex.Message); } conn.Close(); MessageBox.Show("Serverversion : " + version); }

 

10. Wahl der Datenbank

"Die beste" Datenbank gibt es nicht. Jede Datenbank hat so ihre Vor- und Nachteile. Die Datenbank sollte je nach den Anforderungen ausgewählt werden. Folgende Datenbanken stehen unter anderem zur Auswahl :

Microsoft SQL Server 2005/2008 Express Edition

Für eine Datenbank-Entwicklung empfiehlt sich auf jeden Fall Microsoft SQL Server Express. Er ist kostenlos, leistungsfähig und wird gut vom Visual Studio unterstützt. Mit Management Studio Express steht eine umfangreiche Oberfläche für Erstellung und Pflege der Datenbanken zur Verfügung. Bei wachsenden Anforderungen (mehrere CPU, 64 Bit, Replikation, Reporting) kann dann auf eine größere SQL Version umgestiegen werden, Änderungen im Programm sind dabei nicht nötig (Es sei denn der Connectionstring ist im Source codiert).
Der Microsoft SQL Server Express muss zusätzlich zur Applikation auf einem Rechner installiert werden, dafür sollte man sich schon etwas Zeit nehmen, das klappt nicht immer auf Anhieb.
Es können mehrere Benutzer in einem Netzwerk auf einen SQL Server Express zugreifen.

Microsoft SQL Server 2005/2008 Standard, Workgroup und Enterprise

Die großen Brüder des SQL Server Express Edition bieten so einiges mehr, z.B. in den Bereich Replikation, Auswertungen (Reporting Services Server), OLAP (Management Info Systeme). Meistens braucht man das aber nicht (Zumindestens am Anfang).

Die Übersicht über die Features der einzelnen Mitglieder der SQL Server Familie : http://technet.microsoft.com/de-de/library/ms143761.aspx

MySQL

MySQL ist die bekannteste Open-Source-Datenbank, bekanntgeworden durch den Einsatz auf Webservern. Inzwischen sie erwachsen geworden und kann sich neben Microsoft SQL Server und Oracle ohne weoteres behaupten. MySQL ist für so gut wie jedes Betriebssystem erhältlich und sehr schnell. Die Doku ist sehr gut. Inzwischen gibt es einen guten .NET Treiber von MySQL.
Zu beachten : Die eigene Verwendung der Community Version ist kostenlos, die Weitergabe mit der eigenen Applikation ist immer kostenpflichtig (es sei denn die eigene Applikation ist nach GNU lizensiert).

Oracle Database Server

Oracle ist die bekannteste "große" Datenbank, geeignet um riesige Datenmengen zu verwalten und zu bearbeiten. Ist recht teuer, es gibt aber inzwischen eine kostenlose Version (max. 4 GB Datenbankgröße). In vielen Behörden und großen Firmen ist die Verwendung von Oracle als Datenbank vorgeschrieben.

Embedded Datenbanken

Sogenannte Embedded Datenbanken müssen nicht extra installiert werden, die Installation beschränkt sich meistens auf das Kopieren einer oder mehrerer DLL-Dateien. Der Datenbankserver wird dann zusammen mit der Applikation gestartet. Aus diesem Grund kann immer nur ein User auf die Datenbank zugreifen, Zugriff von mehreren Rechnern auf eine Datenbank ist hiermit nicht möglich. Mehrere User von einem Rechner aus geht manchmal.

Microsoft SQL Server 2005 Compact Edition

Der neue SQL Server Compact von Microsoft wurde nicht aus dem normalen SQL Server entwickelt, sondern aus dem SQL Server für Windows Mobile. Deshalb ist sein SQL-Syntax anders. Die Verwaltung der Datenbanken kann auch mit Microsoft Management Studio Express durchgeführt werden.
Für Anwendungen mit nur einem User ist der SQL Server Compact ausreichend schnell und sicher. Die maximale Datenbankgröße beträgt 4 GB.
Der ehemalige Name der Compact Edition ist 'SQL Server Everywhere' und 'SQL Server CE', deshalb finden sich diese beiden Namen noch in Dokumentation und Dateinamen.

PostgreSQL

PostgreSQL ist eine freie Open-Source-Datenbank, die für alle Anwendungen kostenlos ist und auf nahezu allen Betriebssystemen läuft. Sie hat einen großen Sprachumfang (SQL92 und SQL99 Standard) und einige objektrelationale Ansätze. Einige Leute finden sie zu groß und zu langsam. Kann ich aber nicht bestätigen. 

SQL Firebird

SQL Firebird ist eine leistungsfähige Datenbank die es in allen Größen gibt, auch als Embedded-Version. Der SQL-Syntax ist leider (oder zum Glück) anders als beim Microsoft SQL Server.

SQL Lite

SQL Lite ist eine kleine aber feine Datenbank für Embedded Einsatz im Einzelplatzbetrieb. Läuft auch auf Linux und Apple Betriebssystemen.

XML

Bei sehr kleinen Datenmengen kann es ausreichend sein die Daten im XML-Format zu speichern. Man kann XML-Daten mit einem Befehl in ein Dataset speichern und wieder laden (Na gut, das sind dann 2 Befehle).

Access

Der Vollständigkeit halber erwähne ich hier Access, obwohl es meiner Meinung hier nicht dazugehört, weil es keine Datenbank ist. Eine Datenbank sollte Transaktionen und Rollback beherrschen. Access bitte nur benutzen wenn es unbedingt sein, muss, weil Daten bereits in Access vorliegen. Sonst ist SQL Server Express oder SQL Server Compact die bessere Wahl.

 

11. Datenbankunabhängige Programmierung

Das wünscht sich jeder Programmierer, ein Programm schreiben und dann den Anwender aussuchen lassen welche Datenbank benutzt werden soll. Es gab früher schon einmal einen Ansatz für eine datenbankunabhängige Programmierung namens ODBC. Rausgekommen ist allerdings eine langsame und umständliche Lösung, die sehr eingeschränkt ist, weil sie nur den kleinsten gemeinsamen Nenner unterstützt.
Die meisten Datenbanken stellen native .NET-Treiber zur Verfügung, die um einiges schneller, sicherer und komfortabler sind.

Muss man nun für jede Datenbank ein eigenes Programm schreiben ? Nein, zum Glück nicht, denn Microsoft hat mit der Version 2.0 des Frameworks die ProviderFactory eingeführt, eine Klasse mit der alle Datenbanken angesprochen werden können.

Der Namespace heisst System.Data.Common (oben mit using angegeben), ein Programm sieht dann z.B. so aus :

string dbprovider = "System.Data.SqlClient"; // z.B. Microsoft SQL Server
DbProviderFactory factory = DbProviderFactories.GetFactory(dbprovider);
DbConnection conn = factory.CreateConnection();
DbCommand cmd = factory.CreateCommand();
DbCommandBuilder cb = factory.CreateCommandBuilder();

Dieser Programmteil erzeugt Connection, Command und Commandbuilder für einen Datenbankzugriff, der für alle Datenbanken gültig ist. Lediglich der String dbprovider muss angepasst werden.

Toll, oder ?

Ja, im Prinzip schon. Damit dein Programm aber mit mehreren Datenbanken läuft ist noch viel mehr Arbeit notwendig :

Die Datentypen weichen voneinander ab
Die SQL-Kommandos sind leider überhaupt nicht einheitlich
Sonderfunktionen wie Bulk Insert oder Backup sind total verschieden, wenn überhaupt vorhanden
Transaktionsmanagement ist bei jeder Datenbank anders
MySQL und Oracle kennen z.B. keinen Datentyp bit. Oracle bildet alle numerischen Datentypen intern als "numeric" ab und gibt in .NET immer den Datentyp "Decimal" zurück. In den SLQ Befehlen unterscheiden sich die Datenbanken besonders im Kommando "create table" und in allen Kommandos die mit Datum und Zeit zu tun haben. Wenn man in seinem Programm also SQL-Statements benutzt (wird man wohl kaum drumrumkommen) so sind diese oft für jede Datenbank einzeln abzulegen.

Beispiele :

using System.Data;
using System.Data.Common;

public DbCommand CreateCommand() { DbCommand cmd = null; DbProviderFactory factory; if (Parameter.dbprovider == Parameter.DatenbankProvider.MicrosoftSQLServer) { factory = DbProviderFactories.GetFactory("System.Data.SqlClient"); cmd = factory.CreateCommand(); } if (Parameter.dbprovider == Parameter.DatenbankProvider.SQLServerCompactEdition) cmd = new SqlCeCommand(); if (Parameter.dbprovider == Parameter.DatenbankProvider.MySQL) cmd = new MySqlCommand(); if (Parameter.dbprovider == Parameter.DatenbankProvider.OracleSQLServer) cmd = new OracleCommand(); if (Parameter.dbprovider == Parameter.DatenbankProvider.OleDB) cmd = new OleDbCommand(); return cmd; } public RowCount(string tab) { string sqlstr = "select count(*) from " + tab; DbDataReader dr; // DataReader für dieses Befehl
// MS SQL gibt den Datentyp int32 zurück.
// MySQL gibt den Datentyp int64 zurück.

// Oracle gibt den Datentyp decimal zurück. if (dr[0].GetType() == typeof(Int64)) count = (int)(long)dr[0];
else if (dr[0].GetType() == typeof(Decimal)) count = (int)(Decimal)dr[0];
else count = (int)dr[0];
return count; }

 

12. O/R-Mapper

Bei größeren Applikationen greift man normalerweise nicht direkt aus dem Programmteil mit der Anwendungslogik auf die Datenbank zu. In der sogenannten Businesslogik ist es bequemer und sicherer mit Objekten anstatt mit Datasets und Datatables zu arbeiten. Die Umwandlung und den gesamten Datenbankzugriff erledigen die sogenannten O/R-Mapper (Object-Relational-Mapper). Die gibt es z.B. im MyCSharp-Forum oder bei codeproject.com als Projekt, als Freeware (NHibernate, Retina, ActiveRecord, XPO, EntitySpaces) oder auch teuer zu kaufen. Bei großen Applikationen lohnen sie sich aber auf jeden Fall. Microsoft bietet im Framework 3.5 das ADO Entity Framework an, das auf LINQ basiert. Ob das empfehlenwert ist kann ich nicht sagen. Auf jeden Fall vorher vergewissern, ob es für die geplanten Datenbanken auch ein Entity Framework gibt, das sind nämlich nicht viele.

Beispiel für einen Zugriff mit und ohne O/R-Mapper :

// Ohne O/R-Mapper
ds.Tables["Positionen"].Rows[0]["Gesamtpreis"] = (double)ds.Tables["Positionen"].Rows[0]["Menge"] * (double)ds.Tables["Positionen"].Rows[0]["Einzelpreis"];


// Mit O/R-Mapper
po.Gesamtpreis = po.Menge * po.Einzelpreis;

Ich selbst arbeite mit einem selbstgeschriebenen O/R-Mapper. Ob man sich das aber antun soll, sowas selbst zu schreiben, ist sehr umstritten.

Die Architektur meiner Software ist wie folgt aufgebaut :

--------------------------------------
Präsentationslogik
--------------------------------------
Businesslogik
--------------------------------------
DataObjects 
--------------------------------------
Mapping C#-Datentypen / DB-Datentyp
--------------------------------------
DB-Zugriffsschicht
--------------------------------------
Datenbankzugriff für jeden DB-Provider
--------------------------------------
Datenbank
--------------------------------------

Hinweis : Diese aufwändige Grafik wurde erstellt mit notepad.exe

Wenn man in der Businesslogik programmiert muss man nicht wissen welcher Datentyp das dann später in der Datenbank ist : bool ist z.B. bei MySQL TinyInt und bei Oracle decimal.
Wenn eine neue Datenbank hinzufügt werden soll, wie z.B. PostgreSQL, dann muss man nur in der untersten Schicht ein paar Befehle hinzufügen und es läuft dann sofort mit der neuen Datenbank.

 

13. Eine fertige Applikation

In vielen Fällen ist es besser, auf eine fertige Applikation zuzugreifen, als das Rad zum 1000. Mal zu erfinden.

Eine fertige Applikation möchte ich besonders erwähnen : Quasar-3

Quasar-3 beinhaltet Adreßverwaltung, Artikelverwaltung, Auftragsverwaltung und zahlreiche Zusatzmodule wie Webshop, Ebay-Modul, Report-Generator, Textverarbeitung.

Quasar-3 basiert auf dem .NET Framework 3.5 und läuft mit den Datenbanken Microsoft SQL Compact, Microsoft SQL Server (Express), MySQL, Oracle und PostgreSQL.

Quasar-3 bietet Schnittstellen zu MS Word, Excel, Outlook, eBay und E-Shop-Systemen.

Technologisch möchte ich erwähnen : Online Update der Applikation in laufenden Betrieb, Installations-Assistent installiert benötigte Zusatzmodule nach Bedarf nach, einfache und sichere Connectionstringverwaltung für alle Datenbanksysteme, benutzerfreundliche (pessimistische) Sperren mit autom. Freigabe bei Programmabbruch, eigene Backup- und Restore-Routinen auf Serverlaufwerk oder auf lokales Laufwerk.

Eine kostenlose Community Version ist auf www.seven-c.de/cv verfügbar.

Die Datenbankstruktur lege ich auf Anfrage gerne offen. so können eigene Module programmiert werden.

Bei Fragen zu ADO.NET oder Quasar-3 stehe ich gerne zur Verfügung.

B e r n d Q u a m b u s c h
bq (at ) seven-c (punkt) de
06181 / 4375-700