Skip to content

7. Fallstudie mit Firebird 2.1

7.1. Installation der Tools

Folgende Tools müssen installiert werden:

  • SGBD: [http://www.firebirdsql.org/en/firebird-2-1-5/];
  • ein Verwaltungstool: EMS, SQL, Manager für InterBase/Firebird Freeware, [http://www.sqlmanager.net/fr/products/ibfb/manager/download].

In den folgenden Beispielen ist der Benutzer „sysdba“ mit dem Passwort „masterkey“.

Starten wir Firebird und anschließend das Tool [SQL Manager Lite for Firebird], mit dem wir SGBD verwalten werden.

  • In [1] starten wir Firebird über das Startmenü. Hier wurde SGBD nicht als Windows-Dienst installiert;
  • in [2] wird der Dienst gestartet. Unten rechts auf dem Bildschirm wurde ein Symbol angezeigt. Mit einem Rechtsklick darauf kann man den SGBD beenden.

Wir starten nun das Tool [SQL Manager Lite for Firebird], mit dem wir den Dienst SGBD [3] verwalten werden.

  • In [4] legen wir eine neue Datenbank an;
  • in [5] bestätigen wir;
  • in [5] melden wir uns als SYSDBA / masterkey an;
  • In [6] geben wir den Speicherort der Datei an, die erstellt werden soll. Die Datenbank wird nämlich in einer einzigen Datei angelegt;
  • Bei [7] wird der Auftrag SQL bestätigt, der ausgeführt werden soll;
  • In [8] wurde die Datenbank angelegt. Sie muss nun in [EMS Manager] gespeichert werden. Die Informationen sind korrekt. Wir führen [OK] aus;
  • in [9] melden wir uns an;
  • In [10] zeigt [EMS Manager] die Datenbank an, die derzeit noch leer ist.

Wir werden nun ein Projekt VS 2012 mit dieser Datenbank verbinden.

7.2. Erstellung der Datenbank aus den Entitäten

Zunächst duplizieren wir den Projektordner [RdvMedecins-SqlServer-01] in [RdvMedecins-Firebird-01] und [1]:

  • in [2], in VS 2012 löschen wir das Projekt [RdvMedecins-SqlServer-01] aus der Lösung;
  • in [3] wurde das Projekt gelöscht;
  • in [4] fügen wir ein weiteres hinzu. Dieses befindet sich im Ordner [RdvMedecins-Firebird-01], den wir zuvor erstellt haben;
  • In [5] heißt das geladene Projekt [RdvMedecins-SqlServer-01];
  • in [6], dessen Name in [RdvMedecins-Firebird-01] geändert wird
  • In [7] wird der Lösung ein weiteres Projekt hinzugefügt. Dieses stammt aus dem Ordner [RdvMedecins-SqlServer-01] des Projekts, das wir zuvor aus der Lösung entfernt haben;
  • In [8] wurde das Projekt [RdvMedecins-SqlServer-01] wieder in die Lösung aufgenommen.

Das Projekt [RdvMedecins-Firebird-01] ist identisch mit dem Projekt [RdvMedecins-SqlServer-01]. Wir müssen einige Änderungen vornehmen. In [App.config] werden wir die Verbindungszeichenfolge ändern, und [DbProviderFactory] muss an jedes SGBD angepasst werden.


<!-- Verbindungszeichenfolge zur Datenbank -->
  <connectionStrings>
    <add name="monContexte" connectionString="User=SYSDBA;Password=masterkey;Database=D:\data\istia-1213\c#\dvp\Entity Framework\databases\firebird\RDVMEDECINS-EF.GDB;DataSource=localhost;
Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;" providerName="FirebirdSql.Data.FirebirdClient" />
  </connectionStrings>
  <!-- Der Factory-Provider -->
  <system.data>
    <DbProviderFactories>
      <add name="Firebird Client Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.7.7.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c" />
    </DbProviderFactories>
  </system.data>
  • Zeile 3: Benutzername und Passwort sowie der vollständige Pfad zur Firebird-Datenbank;
  • Zeilen 8–10: das DbProviderFactory. Zeile 9 verweist auf ein DLL und ein [FirebirdSql.Data.FirebirdClient], die wir nicht haben. Man erhält sie mit NuGet und [1]:
  • bei [2] geben wir im Suchfeld das Stichwort firebird ein;
  • bei [3] wählen Sie das Paket [Firebird ADO.NET Data Provider] aus. Es handelt sich um einen Konnektor ADO.NET für Firebird;
  • in [4], die neue Referenz;
  • in [5], in [App.config] muss die korrekte Version von DLL eingegeben werden. Diese findet man in den Eigenschaften.

In der Datei [Entites.cs] muss das Schema der zu generierenden Tabellen angepasst werden:


  [Table("MEDECINS")]
  public class Medecin : Personne
  {...}

  [Table("CLIENTS")]
  public class Client : Personne
  {...}

  [Table("CRENEAUX")]
  public class Creneau
  {...}

  [Table("RVS")]
  public class Rv
  {...}

Hier haben die Tabellen kein Schema.

Wir konfigurieren die Ausführung des Projekts:

  • In [1] geben wir der zu generierenden Assembly einen anderen Namen;
  • in [2] legen wir außerdem einen anderen Standard-Namespace fest;
  • in [3] legen wir das auszuführende Programm fest.

Zu diesem Zeitpunkt liegen keine Kompilierungsfehler vor. Führen wir das Programm [CreateDB_01] aus. Dabei tritt folgende Ausnahme auf:

Exception non gérée : System.Data.MetadataException: Le schéma spécifié n'est pas valide. Erreurs :
(11,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(23,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(33,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
(43,6) : erreur 0040: Le type rowversion n'est pas qualifié avec un espace de noms ou un alias. Seuls les types primitifs peuvent être utilisés sans qualification.
   à System.Data.Metadata.Edm.StoreItemCollection.Loader.ThrowOnNonWarningErrors
()
   ...
   à RdvMedecins_01.CreateDB_01.Main(String[] args) dans d:\data\istia-1213\c#\d
vp\Entity Framework\RdvMedecins\RdvMedecins-Oracle-01\CreateDB_01.cs:ligne 15

Wir erinnern uns, dass derselbe Fehler bereits bei MySQL, Oracle und PostgreSQL aufgetreten ist. Dies hängt mit dem Feldtyp Timestamp der Entitäten zusammen. Wir nehmen dieselbe Änderung vor wie bei den beiden vorherigen SGBD. In den Entitäten ersetzen wir die drei Zeilen


    [Column("TIMESTAMP")]
    [Timestamp]
    public byte[] Timestamp { get; set; }

durch die folgenden:


    [ConcurrencyCheck]
    [Column("VERSIONING")]
    public int? Versioning { get; set; }

Wir ändern also den Typ der Spalte von byte[] auf int?. In der Prozedur SGBD verwenden wir gespeicherte Prozeduren, um diese Ganzzahl jedes Mal um eins zu erhöhen, wenn eine Zeile eingefügt oder geändert wird.

Wir nehmen die oben beschriebene Änderung an allen vier Entitäten vor und führen die Anwendung anschließend erneut aus. Daraufhin erhalten wir folgende Fehlermeldung:

1
2
3
4
5
Exception non gérée : FirebirdSql.Data.FirebirdClient.FbException: lock time-out on wait transaction object D:\DATA\ISTIA-1213\C#\DVP\ENTITY FRAMEWORK\DATABASES\FIREBIRD\RDVMEDECINS-EF.GDB ist in Gebrauch ---> FirebirdSql.Data.Common.IscException: Zeitüberschreitung bei der Sperre der wartenden Transaktion
object D:\DATA\ISTIA-1213\C#\DVP\ENTITY FRAMEWORK\DATABASES\FIREBIRD\RDVMEDECINS
-EF.GDB is in use
...
   à RdvMedecins_01.CreateDB_01.Main(String[] args) dans d:\data\istia-1213\c#\dvp\Entity Framework\RdvMedecins\RdvMedecins-Firebird-01\CreateDB_01.cs:Zeile 15

Zeile 1 weist darauf hin, dass die Datenbank verwendet wird. Meines Wissens nach war dies nicht der Fall, und es ist mir nicht gelungen, dieses Problem zu beheben.

Egal. Wir werden die Datenbank [RDVMEDECINS-EF] manuell mit dem Tool [EMS Manager for Firebird] anlegen. Wir beschreiben nicht alle Schritte, sondern nur die wichtigsten.

Die Firebird-Datenbank wird wie folgt aussehen:

Die Tabellen

  • in [1] ist ID ein Primärschlüssel mit dem Attribut Autoincrement. Er wird automatisch von SGBD generiert;

Die verschiedenen Tabellen verfügen über dieselben Primär- und Fremdschlüssel wie in den vorherigen Beispielen. Die Fremdschlüssel haben die Attribute ON, DELETE und CASCADE.

Die Generatoren

Wie bei Oracle und PostgreSQL haben wir Generatoren für fortlaufende Nummern erstellt. Es gibt insgesamt 5 davon: [1].

  • [CLIENTS_ID_GEN] wird zur Generierung des Primärschlüssels der Tabelle [CLIENTS] verwendet;
  • [MEDECINS_ID_GEN] wird zur Generierung des Primärschlüssels der Tabelle [MEDECINS] verwendet;
  • [CRENEAUX_ID_GEN] wird zur Generierung des Primärschlüssels der Tabelle [CRENEAUX] verwendet;
  • [RVS_ID_GEN] wird zur Generierung des Primärschlüssels der Tabelle [RVS] verwendet;
  • [VERSIONS_GEN] wird zur Generierung der Werte der Spalten [VERSIONING] aller Tabellen verwendet.

Trigger

Ein Trigger ist eine Prozedur, die von SGBD vor oder nach einem Ereignis (Einfügen, Ändern, Löschen) in einer Tabelle ausgeführt wird. Wir haben 8 davon: [1]:

Sehen wir uns den Code des Triggers [BI_CLIENTS_ID] an, der die Spalte [ID] der Tabelle [CLIENTS] füllt:

1
2
3
4
5
6
7
8
CREATE TRIGGER BI_CLIENTS_ID FOR CLIENTS
ACTIVE BEFORE INSERT
POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
      NEW.ID = GEN_ID(CLIENTS_ID_GEN, 1);
END^
  • Zeile 2: vor jedem Einfügen in die Tabelle [CLIENTS];
  • Zeilen 6–7: Wenn die Spalte ID den Wert NULL hat, wird ihr der nächste Wert des Zahlengenerators [CLIENTS_ID_GEN] zugewiesen.

Die Trigger [ BI_CLIENTS_ID, BI_MEDECINS_ID, BI_CRENEAUX_ID, BI_RVS_ID] sind alle auf die gleiche Weise aufgebaut.

Sehen wir uns nun den Code DDL des Triggers [CLIENTS_VERSION_TRIGGER] an, der die Spalte [VERSIONING] der Tabelle [CLIENTS] befüllt:

1
2
3
4
5
6
7
CREATE TRIGGER CLIENTS_VERSION_TRIGGER FOR CLIENTS
ACTIVE BEFORE INSERT OR UPDATE
POSITION 1
AS
BEGIN
  NEW."VERSIONING" = GEN_ID(VERSIONS_GEN,1);
END^
  • Zeilen 1–3: vor jeder Operation INSERT oder UPDATE an der Tabelle [CLIENTS];
  • Zeile 6: Die Spalte ["VERSIONING"] erhält den folgenden Wert vom Zahlengenerator [VERSIONS_GEN]. Dieser Generator versorgt die Spalten ["VERSIONING"] der vier Tabellen.

Die Trigger [MEDECINS_VERSION_TRIGGER, CRENEAUX_VERSION_TRIGGER, RVS_VERSION_TRIGGER] funktionieren analog.

Das Skript zur Erstellung der Tabellen der Firebird-Datenbank [RDVMEDECINS-EF] wurde im Ordner [RdvMedecins / databases / Firebird] abgelegt. Der Leser kann es laden und ausführen, um seine Tabellen anzulegen.

Anschließend können die verschiedenen Programme des Projekts ausgeführt werden. Sie liefern dieselben Ergebnisse wie mit dem SQL-Server, mit Ausnahme des Programms [ModifyDetachedEntities], das aus demselben Grund abstürzt, aus dem es auch bei Oracle und MySQL abgestürzt war. Das Problem lässt sich auf die gleiche Weise beheben. Es reicht aus, das Programm [ModifyDetachedEntities] aus dem Projekt [RdvMedecins-Oracle-01] in das Projekt [RdvMedecins-Firebird-01] zu kopieren.

7.3. Mehrschichtige Architektur auf Basis von EF 5

Wir kehren zu unserer in Abschnitt 2 beschriebenen Fallstudie zurück.

Zunächst erstellen wir die Datenzugriffsebene [DAO]. Dazu duplizieren wir das Konsolenprojekt VS 2012 [RdvMedecins-SqlServer-02] in [RdvMedecins-Firebird-02] [1]:

  • in [2], das Projekt [RdvMedecins-SqlServer-02] wird gelöscht;
  • In [3] wird ein bestehendes Projekt zur Lösung hinzugefügt. Es wird aus dem soeben erstellten Ordner [RdvMedecins-Firebird-02] übernommen;
  • In [4] trägt das neue Projekt den Namen des gelöschten Projekts. Wir werden seinen Namen ändern;
  • In [5] haben wir den Namen des Projekts geändert;
  • in [6] werden einige seiner Eigenschaften geändert, wie hier beispielsweise der Name der Assembly;
  • in [7]; der Ordner [Models] wird gelöscht und durch den Ordner [Models] aus dem Projekt [RdvMedecins-Firebird-01] ersetzt. Tatsächlich nutzen beide Projekte dieselben Vorlagen.
  • in [8], die aktuellen Verweise des Projekts;
  • in [9] wurde der Firebird-Konnektor ADO.NET mit dem Tool NuGet hinzugefügt.

In der Datei [App.config] werden die Informationen der SQL-Datenbank durch die der Firebird-Datenbank ersetzt. Diese finden sich in der Datei [App.config] des Projekts [RdvMedecins-Firebird-01]:


<!-- Verbindungszeichenfolge zur Datenbank -->
  <connectionStrings>
    <add name="monContexte" connectionString="User=SYSDBA;Password=masterkey;Database=D:\data\istia-1213\c#\dvp\Entity Framework\databases\firebird\RDVMEDECINS-EF.GDB;DataSource=localhost;
Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;" providerName="FirebirdSql.Data.FirebirdClient" />
  </connectionStrings>
  <!-- Factory-Provider -->
  <system.data>
    <DbProviderFactories>
      <add name="Firebird Client Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.7.7.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c" />
    </DbProviderFactories>
  </system.data>

Auch die von Spring verwalteten Objekte ändern sich. Derzeit haben wir:


  <!-- Spring-Konfiguration -->
  <spring>
    <context>
      <resource uri="config://spring/objects" />
    </context>
    <objects xmlns="http://www.springframework.net">
      <object id="rdvmedecinsDao" type="RdvMedecins.Dao.Dao,RdvMedecins-SqlServer-02" />
    </objects>
</spring>

Zeile 7 verweist auf die Assembly des Projekts [RdvMedecins-SqlServer-02]. Die Assembly lautet nun [RdvMedecins-Firebird-02].

Nachdem dies erledigt ist, können wir den Test der Schicht [DAO] ausführen. Zuvor muss jedoch die Datenbank gefüllt werden (Programm [Fill] des Projekts [RdvMedecins-Firebird-01]). Der Test läuft erfolgreich ab.

Wir erstellen die DLL des Projekts, wie es bereits für das Projekt [RdvMedecins-SqlServer-02] geschehen ist, und sammeln diealle DLL des Projekts in einem Ordner [lib] zusammen, der in [RdvMedecins-Firebird-02] angelegt wurde. Dies sind die Referenzdateien für das nachfolgende Webprojekt [RdvMedecins-Firebird-03].

  

Wir sind nun bereit, die Ebene [ASP.NET] unserer Anwendung zu erstellen:

Wir gehen vom Projekt [RdvMedecins-SqlServer-03] aus. Wir duplizieren den Ordner dieses Projekts in [RdvMedecins-Firebird-03] und [1]:

  • in [2], mit VS 2012 Express für das Web öffnen wir die Lösung aus dem Ordner [RdvMedecins-Firebird-03];
  • in [3] ändern wir sowohl den Namen der Lösung als auch den Namen des Projekts;
  • In [4] werden die aktuellen Projektverweise;
  • in [5] löschen wir sie;
  • in [6], um sie durch Verweise auf die Datei DLL zu ersetzen, die wir gerade in einem Ordner [lib] des Projekts [RdvMedecins-Firebird-02] gespeichert haben.

Nun müssen wir nur noch die Datei [Web.config] ändern. Wir ersetzen ihren aktuellen Inhalt durch den Inhalt der Datei [App.config] aus dem Projekt [RdvMedecins-Firebird-02]. Anschließend führen wir das Webprojekt aus. Es funktioniert. Vergessen Sie nicht, die Datenbank zu füllen, bevor Sie die Webanwendung ausführen.