Wenn Sie ein Abonnement des Magazins 'DATENBANKENTWICKLER' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.
Entity Framework: SQLite verknüpfen
In den letzten Artikel haben wir oft die SQLite-Datenbank als Beispieldatenbank verwendet. Nun kann es allerdings durch einen falschen Connection-String oder eine verschobene, gelöschte oder leere Datenbank dazu kommen, dass die Anwendung nicht über das Entity Framework auf die Datenbank zugreifen kann. Dieser Artikel beschreibt einige Szenarien, in denen das der Fall ist und zeigt, wie Sie beim Start der Anwendung prüfen können, ob die Quell-Datenbank erreichbar ist und diese gegebenenfalls neu auswählen.
Die SQLite-Datenbank ist eine sehr praktische Datenquelle für einfache Anwendungen, die keinen SQL Server benötigen. Sie kommt als eine einzige Datei daher und die Treiber können bequem in ein Projekt integriert werden – auch die Weitergabe ist überhaupt kein Problem. Was aber ein Problem sein könnte, wissen Access-Entwickler, die Datenbanken in Front- und Backend aufgeteilt haben, nur zu gut: Die Datenbankdatei könnte sich nicht an dem Ort befinden, der in der Verbindungszeichenfolge des Frontends angegeben ist.
Mit einem .NET-WPF-Projekt und einer SQLite-Datenbank haben Sie ein klassisches Frontend-Backend-Szenario, wie es auch bei aufgeteilten Access-Datenbanken vorliegt. Im Gegensatz zur Konstellation mit einem SQL Server haben Sie keine Server-Angabe im Connection-String, sondern Sie müssen den Namen der Datenbank, gegebenenfalls mit Angabe des Pfades zu dieser Datenbank, angeben. Wenn Sie ein Entity Data Model zu Ihrem Projekt hinzugefügt und die Datenbankdatei, zum Beispiel Bestellverwaltung.db, als Datenquelle ausgewählt haben, schreibt der Entity Data Model-Assistent eine Verbindungszeichenfolge in die Datei App.config, die etwa wie folgt aussieht:
<configuration>
...
<connectionStrings>
<add name="BestellverwaltungEntities" connectionString="...;provider=System.Data.SQLite.EF6;provider connection
string="data source=c:BeispielBestellverwaltung.db"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Hier sehen Sie, dass der Assistent zum Erstellen des Entity Data Models den absoluten Pfad zur Datenbankdatei Bestellverwaltung.db angegeben hat. Das geht solange gut, wie Sie die Anwendung auf dem Entwicklungsrechner debuggen oder einsetzen und die Datenbank sich an Ort und Stelle befindet.
Wenn Sie jedoch die Anwendung auf einen anderen Rechner verschieben, ist die Wahrscheinlichkeit hoch, dass die Datenbankdatei unter diesem Pfad nicht mehr zu erreichen ist. Ich selbst programmiere beispielsweise auf zwei verschiedenen Rechnern, wobei die Dateien per DropBox jeweils auf den aktuellsten Stand gebracht werden. Und sobald das Projekt samt Datenbankdatei auf dem einen Rechner nicht auf dem gleichen Pfad wie auf dem anderen Rechner liegt, findet eines der beiden Projekte die Datenbankdatei nicht mehr.
Relativ statt absolut
In diesem Fall ist die erste Maßnahme, den Pfad aus der Angabe der Quelldatenbank zu entfernen und nur noch den Dateinamen anzugeben. Das sieht dann in der Datei App.config wie folgt aus:
<configuration>
...
<connectionStrings>
<add name="BestellverwaltungEntities" connectionString="...;provider=System.Data.SQLite.EF6;provider connection
string="data source=Bestellverwaltung.db"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Dies bedeutet nun nichts anderes, als dass die Datenbankdatei nun immer dann erreichbar ist, wenn sich diese im gleichen Verzeichnis wie die .exe-Datei des Projekts befindet.
Mehrbenutzer-Szenario
Das wird in einem Mehrbenutzer-Szenario natürlich nicht mehr funktionieren, denn schon wenn die Anwendung auf zwei Rechnern installiert ist, müsste man auf einem Rechner den absoluten Pfad zu der zu nutzenden Datenbankdatei hinterlegen.
Wir benötigen also einen Mechanismus, der beim Start der Anwendung ausgelöst wird und prüft, ob die zu verwendende Datenbankdatei verfügbar ist. Wenn dies nicht der Fall ist, soll ein Dialog erscheinen, mit dem der Benutzer die Datenbankdatei auswählen soll. Diese Änderung sollte dann optimalerweise irgendwo in den Einstellungen der Datenbank gespeichert und von nun an beim Start abgerufen werden können. Wir beginnen jedoch mit der Prüfung, ob die Datenbankdatei überhaupt an Ort und Stelle ist. Dies erledigen wir beim Start der Anwendung, und zwar beim Aufruf des Hauptfensters.
Beispielkonstellation
Wir erstellen im Fenster MainWindow eine minimale Konfiguration, um die Kunden aus der Datenbank Bestellverwaltung.db in einem DataGrid anzuzeigen. Dazu fügen Sie MainWindow.xaml folgenden Code hinzu:
<Grid>
<DataGrid ItemsSource="{Binding Kunden}"></DataGrid>
</Grid>
Das Code behind-Modul MainWindow.xaml.cs statten wir so aus:
using System.Windows;
using System.Collections.ObjectModel;
namespace TestDatenbankVorhanden {
public partial class MainWindow : Window {
BestellverwaltungEntities dbContext = null;
private ObservableCollection<Kunde> kunden;
public ObservableCollection<Kunde> Kunden {
get { return kunden; }
set { kunden = value; }
}
public MainWindow() {
InitializeComponent();
dbContext = new BestellverwaltungEntities();
kunden = new ObservableCollection<Kunde>(dbContext.Kunden);
DataContext = this;
}
}
}
Damit werden die Daten im Fenster angezeigt.
Datenquelle entfernen
Was geschieht nun, wenn wir die Datenquelle vom gewohnten Ort entfernen? Dazu wechseln Sie im Windows Explorer zum Verzeichnis bin|Debug unterhalb des Projektordners und benennen die Datei Bestellverwaltung.db um, zum Beispiel in _Bestellverwaltung.db. Starten Sie die Anwendung nun von diesem Verzeichnis aus per Doppelklick auf den Namen der .exe-Datei (im Falle der Beispielanwendung TestDatenbankVorhanden.exe). Werden die Daten nun immer noch angezeigt? Dann stehen die Chancen gut, dass Sie im Connection-String noch den absoluten Pfad zur Datei Bestellverwaltung.db stehen haben und die .exe-Datei auf diese Datei zugreift. Entfernen Sie hier zunächst, wie oben beschrieben, die Pfadangabe, sodass nur noch der Dateiname Bestellverwaltung.db im Connection-String steht. Starten Sie das Projekt dann neu, damit die Anwendung mit der neuen Verbindungszeichenfolge im Verzeichnis bin/Debug landet. Dadurch wird nun auch wieder die Datei Bestellverwaltung.db eingetragen, deren Namen Sie ja soeben schon in _Bestellverwaltung.db geändert haben. Beenden Sie die Anwendung also wieder und benennen Sie die Datei Bestellverwaltung.db erneut in _Bestellverwaltung.db um. Starten Sie dann die Anwendung TestDatenbankVorhanden.exe erneut. Was geschieht nun? Normalerweise sollte nun nichts Sichtbares geschehen – die Anwendung wird einfach nicht gestartet. Das liegt daran, dass wir keine Fehlerbehandlung eingebaut haben, die Anwendung aber beim Aufrufen einen Fehler auslöst, denn die Datenquelle ist ja nicht verfügbar. Interessanterweise finden Sie im Verzeichnis bin/Debug aber nun eine neuen Datei namens Bestellverwaltung.db mit einer Größe von 0 KB vor. Dies geschieht, weil das Entity Framework eine neue Datenbankdatei erstellt, wenn beim Versuch des Zugriffs keine entsprechende Datenbankdatei gefunden werden konnte.
Fehler per Exception-Handling aufdecken
Wir wollen die Anwendung also nun mit einer Fehlerbehandlung erweitern, damit wir die Fehlermeldung erhalten und entsprechend darauf reagieren können. Unsere Vermutung ist, dass der Fehler beim Zugriff auf die Kunden-Liste auftritt. Die betroffene Anweisung fassen wir also in einen try-Block ein. Zusammen mit dem catch-Block sieht das Ganze nun wie folgt aus:
try {
kunden = new ObservableCollection<Kunde>(dbContext.Kunden);
}
catch (Exception e) {
MessageBox.Show("Error: " + e.Message + " " + e.InnerException.Message);
}
Wir erhalten dann die folgende Fehlermeldung:
Error:
An error occurred while executing the command definition. See the inner exception for details.
SQL logic error or missing database
no such table: Kunden
Damit können wir etwas anfangen, denn wir wissen ja bereits, dass die Datenbank nicht vorhanden ist. Aber können wir dies auch prüfen, ohne einen Fehler auszulösen? Beispielsweise, indem wir einfach testen, ob die gesuchte Datenbankdatei an der angegebenen Stelle ist? Nein, denn erstens wissen wir ja aktuell gar nicht, wo sich diese befinden soll – dazu müssten wir erst die Verbindungszeichenfolge auslesen. Danach würden wir dann prüfen, ob die entsprechende Datei vorhanden ist. Allerdings kann es auch sein, dass diese Datei beim vorherigen Zugriffsversuch angelegt wurde, aber keine Daten enthält. In diesem Fall würden wir eine Datei vorfinden, erhielten aber einen Fehler, weil die Tabellen, auf die wir zugreifen wollen, nicht mehr vorhanden sind. Der Versuch, auf die Daten einer Tabelle der Datenbank zuzugreifen und diesen Zugriff in eine Ausnahmebehandlung zu integrieren, scheint also durchaus die einfachste Wahl zu sein.
Passende Datenbank auswählen
Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.