Skip to content

4. Fallstudie mit MySQL 5.5.28

4.1. Installation der Tools

Folgende Tools müssen installiert werden:

  • SGBD: [http://dev.mysql.com/downloads/];
  • ein Verwaltungstool: EMS, SQL Manager für MySQL, Freeware [http://www.sqlmanager.net/fr/products/mysql/manager/download].

In den folgenden Beispielen hat der Benutzer „root“ das Passwort „root“.

Starten wir MySQL5. Hier tun wir dies über das Windows-Dienstefenster [1]. In [2] wird SGBD gestartet.

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

  • In [4] legen wir eine neue Datenbank an;
  • in [5] geben wir den Namen der Datenbank an;
  • in [5] melden wir uns als root / root an;
  • in [6] bestätigen wir den Befehl SQL, der ausgeführt werden soll;
  • In [7] wurde die Datenbank angelegt. Sie muss nun in [EMS Manager] gespeichert werden. Die Angaben sind korrekt. Wir führen [OK] aus;
  • in [8] stellen wir eine Verbindung her;
  • In [9] zeigt [EMS Manager] die Datenbank an, die derzeit noch leer ist.

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

4.2. Erstellung der Datenbank anhand der Entitäten

Wir erstellen das folgende Konsolenprojekt VS 2012 [RdvMedecins-MySQL-01] [1]:

  • In [2] fügen wir über NuGet Verweise auf das Projekt hinzu;
  • in [3] wird die Referenz EF 5 hinzugefügt;
  • in [4] ist sie nun in den Referenzen enthalten;
  • In [5] wiederholen wir den Vorgang, um diesmal [MySQL.Data.Entities] hinzuzufügen, bei dem es sich um einen ADO.NET-Konnektor für Entity Framework handelt. Um das Paket zu finden, kann man die Suchfunktion nutzen: [6];
  • Bei der Eingabe von „[7]“ erscheinen zwei Verweise: „[MySQL.Data.Entities]“ und „[MySQL.Data]“, wobei der letztere eine Abhängigkeit des ersteren darstellt.

Nun erstellen wir das Projekt [RdvMedecins-MySQL-01] auf der Grundlage des Projekts [RdvMedecins-SqlServer-01].

  • in [1] kopieren wir die ausgewählten Elemente;
  • in [2] fügen wir sie in das Projekt [RdvMedecins-MySQL-01] ein;
  • in [3]: Da es mehrere Programme mit der Methode [Main] gibt, müssen wir das Startprojekt angeben.

Zu diesem Zeitpunkt sollte die Projektgenerierung erfolgreich sein. Nun ändern wir die Konfigurationsdatei [App.config], die die Verbindungszeichenfolge zur Datenbank konfiguriert, sowie die Datei DbProviderFactory. Sie lautet nun wie folgt:


<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- Weitere Informationen zur Konfiguration des Entity Frameworks finden Sie unter http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  </entityFramework>

  <!-- Verbindungszeichenfolge-->
  <connectionStrings>
    <add name="monContexte"
         connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
         providerName="MySql.Data.MySqlClient" />
  </connectionStrings>
  <!-- der Factory-Provider -->
  <system.data>
    <DbProviderFactories>
      <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
          type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
        />
    </DbProviderFactories>
  </system.data>

</configuration>
  • Zeile 17: die von uns erstellte Datenbankverbindungszeichenfolge MySQL [rdvmedecins-ef];
  • Zeile 24: Die Version muss mit der der Referenz [MySql.Data] des Projekts [1] übereinstimmen:

Auch in der Datei [Entites.cs] sind einige Konfigurationen enthalten, in denen die Namen der Tabellen sowie das Schema, zu dem sie gehören, angegeben werden. Letzteres kann sich je nach SGBD ändern. Dies ist hier der Fall, wo kein Schema vorhanden ist. Die Datei [Entites.cs] sieht wie folgt aus:


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

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

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

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

Führen wir das Programm [CreateDB_01] [2] 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-MySQL-01\CreateDB_01.cs:ligne 15

Der gleiche Fehler tritt viermal auf (Zeilen 2–5). Der Typ rowversion lässt auf das Feld mit der Anmerkung [Timestamp] in den Entitäten schließen:


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

Wir beschließen, diese drei Zeilen durch die folgenden zu ersetzen:


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

Wir ändern den Typ der Spalte von byte[] in DateTime?. Wir tun dies, weil MySQL den Typ [TIMESTAMP] hat, der ein Datum/eine Uhrzeit darstellt, und eine Spalte mit diesem Typ bei jeder Aktualisierung der Zeile automatisch durch MySQL aktualisiert wird. Dies ermöglicht es uns, gleichzeitige Zugriffe zu verwalten.

Die Annotation [Timestamp] kann nur auf eine Spalte vom Typ byte[] angewendet werden. Wir ersetzen sie durch die Annotation [ConcurrencyCheck]. Beide Annotationen regeln den gleichzeitigen Zugriff. Wir führen dies für alle vier Entitäten durch und führen die Anwendung anschließend erneut aus. Daraufhin erhalten wir folgende Fehlermeldung:

1
2
3
4
5
6
7
8
Exception non gérée : MySql.Data.MySqlClient.MySqlException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NOT NULL,        `ProductVersion` mediumtext NOT NULL);

ALTER TABLE `__MigrationH' at line 5
   à MySql.Data.MySqlClient.MySqlStream.ReadPacket()
   à MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId)
   ...
   à RdvMedecins_01.CreateDB_01.Main(String[] args) dans d:\data\istia-1213\c#\d
vp\Entity Framework\RdvMedecins\RdvMedecins-MySQL-01\CreateDB_01.cs:ligne 15

Zeile 1 weist auf einen Syntaxfehler bei der Annotation SQL hin, die von MySQL ausgeführt wird. Da dieser nicht von uns, sondern vom Provider ADO.NET von MySQL generiert wurde, können wir diesen Punkt nicht beheben. Dennoch lässt sich feststellen, dass die folgenden Tabellen von [1] angelegt wurden:

  • In [2] ist die Struktur der Tabelle [clients] [3] zu sehen.

An der generierten Datenbank sind mehrere Änderungen vorzunehmen:

  • Der Typ der Spalte [VERSIONING] ist nicht geeignet. Er muss auf den Typ MySQL [TIMESTAMP] geändert werden;
  • man beachte, dass die Tabelle [rvs] eine Eindeutigkeitsbeschränkung aufweist. Diese wurde bei der Generierung nicht angelegt;
  • der Konnektor ADO.NET von SQL Server hatte Fremdschlüssel mit der Klausel ON DELETE CASCADE generiert. Der Konnektor ADO.NET von MySQL hat dies nicht getan.

Wie bereits beim SQL-Server müssen wir daher die generierte Datenbank ändern. Wir zeigen hier nicht, wie die Änderungen vorgenommen werden. Wir geben lediglich das Skript zur Erstellung der Datenbank an:


# SQL Manager Lite für MySQL 5.3.0.2
# ---------------------------------------
# Host     : localhost
# Port     : 3306
# Datenbank: rdvmedecins-ef


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

SET FOREIGN_KEY_CHECKS=0;

USE `rdvmedecins-ef`;

#
# Struktur der Tabelle „clients“: 
#

CREATE TABLE `clients` (
  `ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
  `PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
  `TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
  `VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=96 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;

#
# Struktur der Tabelle `medecins`: 
#

CREATE TABLE `medecins` (
  `ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
  `PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
  `TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
  `VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=56 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;

#
# Struktur der Tabelle `creneaux`: 
#

CREATE TABLE `creneaux` (
  `ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `HDEBUT` INTEGER(11) NOT NULL,
  `MDEBUT` INTEGER(11) NOT NULL,
  `HFIN` INTEGER(11) NOT NULL,
  `MFIN` INTEGER(11) NOT NULL,
  `MEDECIN_ID` INTEGER(11) NOT NULL,
  `VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY USING BTREE (`ID`) COMMENT '',
   INDEX `MEDECIN_ID` USING BTREE (`MEDECIN_ID`) COMMENT '',
  CONSTRAINT `creneaux_ibfk_1` FOREIGN KEY (`MEDECIN_ID`) REFERENCES `medecins` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=472 AVG_ROW_LENGTH=455 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;

#
# Struktur der Tabelle `rvs`: 
#

CREATE TABLE `rvs` (
  `ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `JOUR` DATE NOT NULL,
  `CRENEAU_ID` INTEGER(11) NOT NULL,
  `CLIENT_ID` INTEGER(11) NOT NULL,
  `VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY USING BTREE (`ID`) COMMENT '',
  UNIQUE INDEX `CRENEAU_ID_JOUR` USING BTREE (`JOUR`, `CRENEAU_ID`) COMMENT '',
   INDEX `CRENEAU_ID` USING BTREE (`CRENEAU_ID`) COMMENT '',
   INDEX `CLIENT_ID` USING BTREE (`CLIENT_ID`) COMMENT '',
  CONSTRAINT `rvs_ibfk_2` FOREIGN KEY (`CLIENT_ID`) REFERENCES `clients` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `rvs_ibfk_1` FOREIGN KEY (`CRENEAU_ID`) REFERENCES `creneaux` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=28 AVG_ROW_LENGTH=16384 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
  • Zeilen 22, 38, 54, 74: Die Primärschlüssel ID der Tabellen sind vom Typ AUTO_INCREMENT und wurden somit von MySQL generiert;
  • Zeilen 26, 42, 60, 78: Die Spalte VERSIONING hat den Typ TIMESTAMP und wird bei einem INSERT oder einem UPDATE aktualisiert;
  • Zeile 63: Der Fremdschlüssel von der Tabelle [creneaux] zur Tabelle [medecins] mit der Klausel ON DELETE CASCADE;
  • Zeile 80: die Eindeutigkeitsbeschränkung der Tabelle [rvs];
  • Zeile 83: der Fremdschlüssel der Tabelle [rvs] zur Tabelle [creneaux] mit der Klausel ON DELETE CASCADE;
  • Zeile 84: Der Fremdschlüssel der Tabelle [rvs] zur Tabelle [clients] mit der Klausel ON DELETE CASCADE;

Das Skript zur Erstellung der Datenbanktabellen MySQL und [rvmedecins-ef] wurde im Ordner [RdvMedecins / databases / mysql] 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 Server SQL, mit Ausnahme des Programms [ModifyDetachedEntities], das abstürzt. Um zu verstehen, warum dies geschieht, kann man sich das Ergebnis des Programms [ModifyAtttachedEntities] ansehen:

1
2
3
4
5
6
7
8
client1--avant
Client [,xx,xx,xx,]
client1--après
Client [86,xx,xx,xx,]
client2
Client [86,xx,xx,xx,11/10/2012 11:31:12]
client3
Client [86,xx,xx,yy,11/10/2012 11:31:12]
  • Zeilen 1–2: ein Client vor dem Speichern des Kontexts;
  • Zeilen 3–4: der Client nach der Speicherung. Er hat einen Primärschlüssel, aber keinen Wert für sein Feld [Versioning], während SQL Server das Feld [Timestamp] der Entität aktualisiert hat.

Sehen wir uns nun den Code des Programms [ModifyDetachedEntities] an, das abstürzt:


using System;
...

namespace RdvMedecins_01
{
  class ModifyDetachedEntities
  {
    static void Main(string[] args)
    {
      Client client1;

      // Die aktuelle Datenbank wird geleert
      Erase();
      // Ein Kunde wird hinzugefügt
      using (var context = new RdvMedecinsContext())
      {
        // Kundenanlegung
        client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
        // Hinzufügen des Kunden zum Kontext
        context.Clients.Add(client1);
        // Speichern des Kontexts
        context.SaveChanges();
      }
      // Datenbank anzeigen
      Dump("1-----------------------------");
      // Kunde1 ist nicht im Kontext enthalten – er wird geändert
      client1.Nom = "y";
      // Änderung einer Entität außerhalb des Kontexts
      using (var context = new RdvMedecinsContext())
      {
        // Hier haben wir einen neuen leeren Kontext
        // „client1“ wird in geänderten Zustand in den Kontext aufgenommen
        context.Entry(client1).State = EntityState.Modified;
        // Der Kontext wird gespeichert
        context.SaveChanges();
      }
      ...
    }

    static void Erase()
    {
      ...
    }

    static void Dump(string str)
    {
      ...
    }
  }
}
  • Zeile 20: Ein Kunde wird gespeichert. Er erhält dabei seinen Primärschlüssel, jedoch anhand seiner Version;
  • Zeile 33: Es wird eine Änderung an „client1“ vorgenommen. Diese schlägt fehl, da er nicht die in der Datenbank vorhandene Version hat.

Das Problem lässt sich beheben, indem man den folgenden Code zwischen Zeile 25 und 26 einfügt:


      // „client1“ wird abgerufen, um dessen Version zu erhalten
      using (var context = new RdvMedecinsContext())
      {
        // „client2“ wird sich im Kontext befinden
        Client client2 = context.Clients.Find(client1.Id);
        // Die Version von „client1“ wird auf die von „client2“ gesetzt
        client1.Versioning = client2.Versioning;
}

Nun hat die Entität [client1] dieselbe Version wie in der Datenbank und kann daher für eine Aktualisierung der Zeile in der Datenbank verwendet werden.

4.3. Mehrschichtige Architektur auf Basis von EF 5

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

Wir beginnen mit der Erstellung der Datenzugriffsebene [DAO]. Dazu erstellen wir das Konsolenprojekt VS 2012 [RdvMedecins-MySQL-02] [1]:

  • in [2] werden die Referenzen [Common.Logging, EntityFramework, MySql.Data, MySql.Data.Entity, Spring.Core] zusammen mit NuGet hinzugefügt;
  • in [3] wird der Ordner [Models] aus dem Projekt [RdvMedecins-MySQL-01] kopiert;
  • In [4] werden die Ordner [Dao, Exception, Tests] und die Datei [App.config] aus dem Projekt [RdvMedecins-SqlServer-02] kopiert;
  • in [5] wurde die Datei [Program.cs] gelöscht;
  • in [6] ist das Projekt so konfiguriert, dass das Testprogramm der Ebene [DAO] ausgeführt wird.

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


<!-- Verbindungszeichenfolge-->
  <connectionStrings>
    <add name="monContexte"
         connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
         providerName="MySql.Data.MySqlClient" />
  </connectionStrings>
  <!-- Der Factory-Provider -->
  <system.data>
    <DbProviderFactories>
      <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
          type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
        />
    </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-MySQL-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-MySQL-01]). Der Test läuft erfolgreich ab.

Wir erstellen die Datei 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-MySQL-02] angelegt wurde. Dies sind die Referenzdateien für das nachfolgende Webprojekt [RdvMedecins-MySQL-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-MySQL-03] und [1]:

  • In [2], mit VS 2012 Express für das Web, öffnen wir die Lösung aus dem Ordner [RdvMedecins-MySQL-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-MySQL-02] gespeichert haben.

Nun müssen wir nur noch die Datei [Web.config] bearbeiten. Wir ersetzen ihren aktuellen Inhalt durch den Inhalt der Datei [App.config] aus dem Projekt [RdvMedecins-MySQL-02]. Anschließend führen wir das Webprojekt aus. Es funktioniert.

4.4. Conclusion

Fassen wir zusammen, was getan wurde, um vom Server SGBD SQL auf den Server SGBD MySQL umzusteigen:

  • Das Feld, das zur Verwaltung der Zugriffskonkurrenz auf die Entitäten diente, wurde geändert. Seine Version auf dem SQL-Server lautete:

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

Sie lautet nun:


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

mit MySQL;

  • die Anmerkungen [Table], die eine Entität mit einer Tabelle verknüpfen, wurden geändert;
  • die Datenbankverbindungszeichenfolge und [DbProviderFactory] wurden in den Konfigurationsdateien [App.config] und [Web.config] geändert;
  • Nach dem Speichern in der Datenbank verfügte eine Entität SQL Server sowohl über ihren Primärschlüssel als auch über ihren Timestamp. Mit MySQL verfügte sie nur über ihren Primärschlüssel. Dies führte zu einer Codeänderung.

Letztendlich waren es nur relativ wenige Änderungen, aber es war dennoch notwendig, den Code zu überarbeiten. Wir wiederholen denselben Vorgang für drei weitere SGBD:

  • SGBD Oracle Database Express Edition 11g Release 2;
  • SGBD PostgreSQL 9.2.1;
  • SGBD Firebird 2.1.